From 698d54eeee9f32916c448a53a51386da02a7ee70 Mon Sep 17 00:00:00 2001 From: David Losert Date: Mon, 26 Feb 2024 20:27:34 +0100 Subject: [PATCH] feat: Add trend indicator (#323) * refactor: Adds folders for more clarity * feat: Adds feature to show trend indicator by comparing json summaries * feat: Adjusts target in report * chore: adjusts output design and adds test export * tests: Fixes tests * docs: Includes docs for the feature --- README.md | 82 ++++++++- action.yml | 9 +- docs/coverage-report-trend-indicator.png | Bin 0 -> 85316 bytes package.json | 1 + src/generateSummaryTableHtml.ts | 56 ------ src/icons.ts | 4 + src/index.ts | 25 ++- src/{ => inputs}/FileCoverageMode.test.ts | 0 src/{ => inputs}/FileCoverageMode.ts | 0 src/{ => inputs}/getPullChanges.ts | 1 - src/{ => inputs}/getViteConfigPath.test.ts | 1 + src/{ => inputs}/getViteConfigPath.ts | 0 src/{ => inputs}/options.ts | 10 +- .../parseCoverageThresholds.test.ts | 2 +- src/{ => inputs}/parseCoverageThresholds.ts | 2 +- src/{ => inputs}/parseJsonReports.ts | 4 +- .../generateFileCoverageHtml.test.ts | 12 +- src/{ => report}/generateFileCoverageHtml.ts | 7 +- src/{ => report}/generateFileUrl.ts | 0 src/{ => report}/generateHeadline.test.ts | 0 src/{ => report}/generateHeadline.ts | 0 .../generateSummaryTableHtml.test.ts | 81 +++++++-- src/report/generateSummaryTableHtml.ts | 88 ++++++++++ .../getUncoveredLinesFromStatements.test.ts | 2 +- .../getUncoveredLinesFromStatements.ts | 2 +- test/exportTestTable.ts | 31 ++++ .../coverage/coverage-summary-compare.json | 164 ++++++++++++++++++ 27 files changed, 474 insertions(+), 110 deletions(-) create mode 100644 docs/coverage-report-trend-indicator.png delete mode 100644 src/generateSummaryTableHtml.ts rename src/{ => inputs}/FileCoverageMode.test.ts (100%) rename src/{ => inputs}/FileCoverageMode.ts (100%) rename src/{ => inputs}/getPullChanges.ts (96%) rename src/{ => inputs}/getViteConfigPath.test.ts (99%) rename src/{ => inputs}/getViteConfigPath.ts (100%) rename src/{ => inputs}/options.ts (82%) rename src/{ => inputs}/parseCoverageThresholds.test.ts (94%) rename src/{ => inputs}/parseCoverageThresholds.ts (96%) rename src/{ => inputs}/parseJsonReports.ts (93%) rename src/{ => report}/generateFileCoverageHtml.test.ts (94%) rename src/{ => report}/generateFileCoverageHtml.ts (95%) rename src/{ => report}/generateFileUrl.ts (100%) rename src/{ => report}/generateHeadline.test.ts (100%) rename src/{ => report}/generateHeadline.ts (100%) rename src/{ => report}/generateSummaryTableHtml.test.ts (52%) create mode 100644 src/report/generateSummaryTableHtml.ts rename src/{ => report}/getUncoveredLinesFromStatements.test.ts (97%) rename src/{ => report}/getUncoveredLinesFromStatements.ts (92%) create mode 100644 test/exportTestTable.ts create mode 100644 test/mockReports/coverage/coverage-summary-compare.json diff --git a/README.md b/README.md index d7396d3..ec6c2f6 100644 --- a/README.md +++ b/README.md @@ -75,15 +75,16 @@ This action requires the `pull-request: write` permission to add a comment to yo ### Options -| Option | Description | Default | -| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| `working-directory` | The main path to search for coverage- and configuration files (adjusting this is especially useful in monorepos). | `./` | -| `json-summary-path` | The path to the json summary file. | `${working-directory}/coverage/coverage-summary.json` | -| `json-final-path` | The path to the json final file. | `${working-directory}/coverage/coverage-final.json` | -| `vite-config-path` | The path to the vite config file. Will check the same paths as vite and vitest | Checks pattern `${working-directory}/vite[st].config.{t\|mt\|ct\|j\|mj\|cj}s` | -| `github-token` | A GitHub access token with permissions to write to issues (defaults to `secrets.GITHUB_TOKEN`). | `${{ github.token }}` | -| `file-coverage-mode` | Defines how file-based coverage is reported. Possible values are `all`, `changes` or `none`. | `changes` | -| `name` | Give the report a custom name. This is useful if you want multiple reports for different test suites within the same PR. Needs to be unique. | '' | +| Option | Description | Default | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | +| `working-directory` | The main path to search for coverage- and configuration files (adjusting this is especially useful in monorepos). | `./` | +| `json-summary-path` | The path to the json summary file. | `${working-directory}/coverage/coverage-summary.json` | +| `json-final-path` | The path to the json final file. | `${working-directory}/coverage/coverage-final.json` | +| `vite-config-path` | The path to the vite config file. Will check the same paths as vite and vitest | Checks pattern `${working-directory}/vite[st].config.{t\|mt\|ct\|j\|mj\|cj}s` | +| `github-token` | A GitHub access token with permissions to write to issues (defaults to `secrets.GITHUB_TOKEN`). | `${{ github.token }}` | +| `file-coverage-mode` | Defines how file-based coverage is reported. Possible values are `all`, `changes` or `none`. | `changes` | +| `name` | Give the report a custom name. This is useful if you want multiple reports for different test suites within the same PR. Needs to be unique. | '' | +| `json-summary-compare-path` | The path to the json summary file to compare against. If given, will display a trend indicator and the difference in the summary. Respects the `working-directory` option. | undefined | #### File Coverage Mode @@ -142,6 +143,69 @@ With the above configuration, the report would appear as follows: If no thresholds are defined, the status will display as '🔵'. +### Coverage Trend Indicator + +By using the `json-summary-compare-path` option, the action will display both a trend indicator and the coverage difference in the summary. This feature is particularly useful for tracking changes between the main branch and a previous run. + +![Screenshot of the action-result showcasing the trend indicator](./docs/coverage-report-trend-indicator.png) + +The most straightforward method to obtain the comparison file within a pull request is to run the tests and generate the coverage for the target branch within a matrix job: + +```yml +name: "Test" +on: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + branch: + - ${{ github.head_ref }} + - "main" + + permissions: + # Required to checkout the code + contents: read + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ matrix.branch }} + - name: "Install Node" + uses: actions/setup-node@v4 + with: + node-version: "20.x" + - name: "Install Deps" + run: npm install + - name: "Test" + run: npx vitest --coverage.enabled true + - name: "Upload Coverage" + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.branch }} + path: coverage + + report-coverage: + needs: test + runs-on: ubuntu-latest + steps: + - name: "Download Coverage Artifacts" + uses: actions/download-artifact@v4 + with: + name: coverage-${{ github.head_ref }} + path: coverage + - uses: actions/download-artifact@v4 + with: + name: coverage-main + path: coverage-main + - name: "Report Coverage" + uses: davelosert/vitest-coverage-report-action@v2 + with: + json-summary-compare-path: coverage-main/coverage-summary.json +``` + ### Workspaces If you're using a monorepo with [Vitest Workspaces](https://vitest.dev/guide/workspace.html) and running Vitest from your project's root, Vitest will disregard the `coverage` property in individual project-level Vite configuration files. This is because some [configuration options](https://vitest.dev/guide/workspace.html#configuration), such as coverage, apply to the entire workspace and are not allowed in a project config. diff --git a/action.yml b/action.yml index 4620230..496fbf3 100644 --- a/action.yml +++ b/action.yml @@ -13,14 +13,17 @@ inputs: required: false description: 'The path to the json summary file. Uses "coverage/coverage-summary.json" by default.' default: coverage/coverage-summary.json - file-coverage-mode: + json-summary-compare-path: required: false - description: 'How to show summary for files coverage. Uses "changes" by default.' - default: changes + description: 'The path to the json summary file of the previous run to get trend indicators.' json-final-path: required: false description: 'The path to the json final file. Uses "coverage/coverage-final.json" by default.' default: coverage/coverage-final.json + file-coverage-mode: + required: false + description: 'How to show summary for files coverage. Uses "changes" by default.' + default: changes working-directory: required: false description: 'Custom working directory' diff --git a/docs/coverage-report-trend-indicator.png b/docs/coverage-report-trend-indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..a12418dce5823b09f4f76beed92ff4c483525217 GIT binary patch literal 85316 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 DhP=|V literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 3b6194f..ebc2194 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "test": "vitest", "test:coverage": "vitest run --coverage.enabled true", + "test:export": "npx ts-node test/exportTestTable.ts", "build": "rm -rf dist && node esbuild.cjs", "start": "npm run build && node dist/index.js", "typecheck": "npx tsc --noEmit" diff --git a/src/generateSummaryTableHtml.ts b/src/generateSummaryTableHtml.ts deleted file mode 100644 index 3525180..0000000 --- a/src/generateSummaryTableHtml.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { icons } from './icons'; -import { oneLine } from 'common-tags'; -import { Thresholds } from './types/Threshold'; -import { CoverageReport, ReportNumbers } from './types/JsonSummary'; - -const generateTableRow = ({ reportNumbers, category, threshold }: { reportNumbers: ReportNumbers; category: string; threshold?: number; }): string => { - - let status = icons.blue; - let percent = `${reportNumbers.pct}%`; - - if(threshold) { - status = reportNumbers.pct >= threshold ? icons.green : icons.red; - percent = `${percent} / ${threshold}%`; - } - - return ` - ${status} - ${category} - ${percent} - ${reportNumbers.covered} / ${reportNumbers.total} - ` -} - - -const generateSummaryTableHtml = (jsonReport: CoverageReport, thresholds: Thresholds = {}): string => { - return oneLine` - - - - - - - - - - - - ${generateTableRow({ reportNumbers: jsonReport.lines, category: 'Lines', threshold: thresholds.lines })} - - - ${generateTableRow({ reportNumbers: jsonReport.statements, category: 'Statements', threshold: thresholds.statements })} - - - ${generateTableRow({ reportNumbers: jsonReport.functions, category: 'Functions',threshold: thresholds.functions })} - - - ${generateTableRow({ reportNumbers: jsonReport.branches, category: 'Branches', threshold: thresholds.branches })} - - -
StatusCategoryPercentageCovered / Total
- ` -} - -export { - generateSummaryTableHtml -}; diff --git a/src/icons.ts b/src/icons.ts index be92c2e..aaef5c1 100644 --- a/src/icons.ts +++ b/src/icons.ts @@ -2,6 +2,10 @@ const icons = { red: '🔴', green: '🟢', blue: '🔵', + increase: '⬆️', + decrease: '⬇️', + equal: '🟰', + target: '🎯' } export { diff --git a/src/index.ts b/src/index.ts index 0fc5779..ec48bb4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,27 +1,34 @@ -import { generateSummaryTableHtml } from './generateSummaryTableHtml.js'; -import { parseVitestJsonFinal, parseVitestJsonSummary } from './parseJsonReports.js'; +import { FileCoverageMode } from './inputs/FileCoverageMode.js' +import { generateFileCoverageHtml } from './report/generateFileCoverageHtml.js'; +import { generateHeadline } from './report/generateHeadline.js'; +import { generateSummaryTableHtml } from './report/generateSummaryTableHtml.js'; +import { getPullChanges } from './inputs/getPullChanges.js'; +import { parseVitestJsonFinal, parseVitestJsonSummary } from './inputs/parseJsonReports.js'; +import { readOptions } from './inputs/options.js'; +import { RequestError } from '@octokit/request-error' import { writeSummaryToPR } from './writeSummaryToPR.js'; import * as core from '@actions/core'; import * as github from '@actions/github'; -import { RequestError } from '@octokit/request-error' -import { generateFileCoverageHtml } from './generateFileCoverageHtml.js'; -import { getPullChanges } from './getPullChanges.js'; -import { FileCoverageMode } from './FileCoverageMode.js' -import { readOptions } from './options.js'; -import { generateHeadline } from './generateHeadline.js'; const run = async () => { const { fileCoverageMode, jsonFinalPath, jsonSummaryPath, + jsonSummaryComparePath, name, thresholds, workingDirectory } = await readOptions(); const jsonSummary = await parseVitestJsonSummary(jsonSummaryPath); - const tableData = generateSummaryTableHtml(jsonSummary.total, thresholds); + + let jsonSummaryCompare; + if(jsonSummaryComparePath) { + jsonSummaryCompare = await parseVitestJsonSummary(jsonSummaryComparePath); + } + + const tableData = generateSummaryTableHtml(jsonSummary.total, thresholds, jsonSummaryCompare?.total); const summary = core.summary .addHeading(generateHeadline({ workingDirectory, name }), 2) .addRaw(tableData) diff --git a/src/FileCoverageMode.test.ts b/src/inputs/FileCoverageMode.test.ts similarity index 100% rename from src/FileCoverageMode.test.ts rename to src/inputs/FileCoverageMode.test.ts diff --git a/src/FileCoverageMode.ts b/src/inputs/FileCoverageMode.ts similarity index 100% rename from src/FileCoverageMode.ts rename to src/inputs/FileCoverageMode.ts diff --git a/src/getPullChanges.ts b/src/inputs/getPullChanges.ts similarity index 96% rename from src/getPullChanges.ts rename to src/inputs/getPullChanges.ts index 12e9b1c..f436009 100644 --- a/src/getPullChanges.ts +++ b/src/inputs/getPullChanges.ts @@ -56,4 +56,3 @@ export async function getPullChanges(fileCoverageMode: FileCoverageMode): Promis core.endGroup() } } - diff --git a/src/getViteConfigPath.test.ts b/src/inputs/getViteConfigPath.test.ts similarity index 99% rename from src/getViteConfigPath.test.ts rename to src/inputs/getViteConfigPath.test.ts index c4ec262..1ede6f2 100644 --- a/src/getViteConfigPath.test.ts +++ b/src/inputs/getViteConfigPath.test.ts @@ -7,6 +7,7 @@ describe("getViteConfigPath", () => { const mockWorkingDirectory = path.resolve( __dirname, "..", + '..', "test", "mockConfig" ); diff --git a/src/getViteConfigPath.ts b/src/inputs/getViteConfigPath.ts similarity index 100% rename from src/getViteConfigPath.ts rename to src/inputs/getViteConfigPath.ts diff --git a/src/options.ts b/src/inputs/options.ts similarity index 82% rename from src/options.ts rename to src/inputs/options.ts index bcbbceb..096717f 100644 --- a/src/options.ts +++ b/src/inputs/options.ts @@ -14,6 +14,13 @@ async function readOptions() { const jsonSummaryPath = path.resolve(workingDirectory, core.getInput('json-summary-path')); const jsonFinalPath = path.resolve(workingDirectory, core.getInput('json-final-path')); + + const jsonSummaryCompareInput = core.getInput('json-summary-compare-path'); + let jsonSummaryComparePath; + if(jsonSummaryCompareInput) { + jsonSummaryComparePath = path.resolve(workingDirectory, jsonSummaryCompareInput); + } + const name = core.getInput('name'); // ViteConfig is optional, as it is only required for thresholds. If no vite config is provided, we will not include thresholds in the final report. @@ -24,9 +31,10 @@ async function readOptions() { fileCoverageMode, jsonFinalPath, jsonSummaryPath, + jsonSummaryComparePath, name, thresholds, - workingDirectory + workingDirectory, } } diff --git a/src/parseCoverageThresholds.test.ts b/src/inputs/parseCoverageThresholds.test.ts similarity index 94% rename from src/parseCoverageThresholds.test.ts rename to src/inputs/parseCoverageThresholds.test.ts index 2f3ae3d..ae3fe85 100644 --- a/src/parseCoverageThresholds.test.ts +++ b/src/inputs/parseCoverageThresholds.test.ts @@ -9,7 +9,7 @@ vi.mock('@actions/core', async (importOriginal) => ({ })); describe('generateTableData', () => { - const mockConfigPath = path.resolve(__dirname, '..', 'test', 'mockConfig'); + const mockConfigPath = path.resolve(__dirname, '..', '..', 'test', 'mockConfig'); const getConfig = (configName: string) => path.resolve(mockConfigPath, configName) it('returns no thresholds if config file can not be found.', async (): Promise => { diff --git a/src/parseCoverageThresholds.ts b/src/inputs/parseCoverageThresholds.ts similarity index 96% rename from src/parseCoverageThresholds.ts rename to src/inputs/parseCoverageThresholds.ts index dd24457..f1c901c 100644 --- a/src/parseCoverageThresholds.ts +++ b/src/inputs/parseCoverageThresholds.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import * as core from '@actions/core'; import { promises as fs } from 'fs'; -import { Thresholds } from './types/Threshold'; +import { Thresholds } from '../types/Threshold'; const regex100 = /100"?\s*:\s*true/; const regexStatements = /statements\s*:\s*(\d+)/; diff --git a/src/parseJsonReports.ts b/src/inputs/parseJsonReports.ts similarity index 93% rename from src/parseJsonReports.ts rename to src/inputs/parseJsonReports.ts index 6ad889c..c2002cc 100644 --- a/src/parseJsonReports.ts +++ b/src/inputs/parseJsonReports.ts @@ -1,8 +1,8 @@ import { readFile } from 'node:fs/promises'; import * as core from '@actions/core'; import path from 'node:path'; -import { JsonFinal } from './types/JsonFinal'; -import { JsonSummary } from './types/JsonSummary'; +import { JsonFinal } from '../types/JsonFinal'; +import { JsonSummary } from '../types/JsonSummary'; import { stripIndent } from 'common-tags'; const parseVitestCoverageReport = async (jsonPath: string): Promise => { diff --git a/src/generateFileCoverageHtml.test.ts b/src/report/generateFileCoverageHtml.test.ts similarity index 94% rename from src/generateFileCoverageHtml.test.ts rename to src/report/generateFileCoverageHtml.test.ts index 5a4df1a..fd877b8 100644 --- a/src/generateFileCoverageHtml.test.ts +++ b/src/report/generateFileCoverageHtml.test.ts @@ -1,11 +1,11 @@ -import { createJsonFinalEntry } from './types/JsonFinalMockFactory'; +import { createJsonFinalEntry } from '../types/JsonFinalMockFactory'; import { generateFileCoverageHtml } from './generateFileCoverageHtml'; -import { getTableLine } from '../test/queryHelper'; -import { JsonFinal } from './types/JsonFinal'; -import { JsonSummary } from './types/JsonSummary'; -import { createMockCoverageReport, createMockJsonSummary, createMockReportNumbers } from './types/JsonSummaryMockFactory'; +import { getTableLine } from '../../test/queryHelper'; +import { JsonFinal } from '../types/JsonFinal'; +import { JsonSummary } from '../types/JsonSummary'; +import { createMockCoverageReport, createMockJsonSummary, createMockReportNumbers } from '../types/JsonSummaryMockFactory'; import { describe, it, expect } from 'vitest'; -import { FileCoverageMode } from './FileCoverageMode'; +import { FileCoverageMode } from '../inputs/FileCoverageMode'; import * as path from 'path'; const workspacePath = process.cwd(); diff --git a/src/generateFileCoverageHtml.ts b/src/report/generateFileCoverageHtml.ts similarity index 95% rename from src/generateFileCoverageHtml.ts rename to src/report/generateFileCoverageHtml.ts index 83c5324..b0ba9d5 100644 --- a/src/generateFileCoverageHtml.ts +++ b/src/report/generateFileCoverageHtml.ts @@ -1,11 +1,10 @@ import * as path from 'path' -import * as core from '@actions/core' import { generateBlobFileUrl } from './generateFileUrl' import { LineRange, getUncoveredLinesFromStatements } from './getUncoveredLinesFromStatements' -import { JsonFinal } from './types/JsonFinal' -import { JsonSummary } from './types/JsonSummary' +import { JsonFinal } from '../types/JsonFinal' +import { JsonSummary } from '../types/JsonSummary' import { oneLine } from 'common-tags' -import { FileCoverageMode } from './FileCoverageMode' +import { FileCoverageMode } from '../inputs/FileCoverageMode' type FileCoverageInputs = { jsonSummary: JsonSummary; diff --git a/src/generateFileUrl.ts b/src/report/generateFileUrl.ts similarity index 100% rename from src/generateFileUrl.ts rename to src/report/generateFileUrl.ts diff --git a/src/generateHeadline.test.ts b/src/report/generateHeadline.test.ts similarity index 100% rename from src/generateHeadline.test.ts rename to src/report/generateHeadline.test.ts diff --git a/src/generateHeadline.ts b/src/report/generateHeadline.ts similarity index 100% rename from src/generateHeadline.ts rename to src/report/generateHeadline.ts diff --git a/src/generateSummaryTableHtml.test.ts b/src/report/generateSummaryTableHtml.test.ts similarity index 52% rename from src/generateSummaryTableHtml.test.ts rename to src/report/generateSummaryTableHtml.test.ts index f384670..0600a8c 100644 --- a/src/generateSummaryTableHtml.test.ts +++ b/src/report/generateSummaryTableHtml.test.ts @@ -1,14 +1,14 @@ import { generateSummaryTableHtml } from './generateSummaryTableHtml'; -import { getTableLine } from '../test/queryHelper'; -import { icons } from './icons'; -import { Thresholds } from './types/Threshold'; -import { createMockCoverageReport, createMockReportNumbers } from './types/JsonSummaryMockFactory'; +import { getTableLine } from '../../test/queryHelper'; +import { icons } from '../icons'; +import { Thresholds } from '../types/Threshold'; +import { createMockCoverageReport, createMockReportNumbers } from '../types/JsonSummaryMockFactory'; import { describe, it, expect } from 'vitest'; describe('generateSummaryTabelHtml()', () => { it('generates the headline', () => { const mockReport = createMockCoverageReport(); - const summaryHtml = generateSummaryTableHtml(mockReport); + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, undefined); const headline = getTableLine(0, summaryHtml); expect(headline).toContain('Status'); @@ -19,7 +19,7 @@ describe('generateSummaryTabelHtml()', () => { it('generates all categories as rows', async (): Promise => { const mockReport = createMockCoverageReport(); - const summaryHtml = generateSummaryTableHtml(mockReport); + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, undefined); expect(getTableLine(1, summaryHtml)).toContain('Lines'); expect(getTableLine(2, summaryHtml)).toContain('Statements'); @@ -30,7 +30,7 @@ describe('generateSummaryTabelHtml()', () => { it('adds status blue-circle if no threshold provided.', async (): Promise => { const mockReport = createMockCoverageReport(); - const summaryHtml = generateSummaryTableHtml(mockReport); + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, undefined); expect(summaryHtml).toContain(icons.blue); }); @@ -41,7 +41,7 @@ describe('generateSummaryTabelHtml()', () => { lines: createMockReportNumbers({ pct: 80 }) }); - const summaryHtml = generateSummaryTableHtml(mockReport); + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, undefined); expect(getTableLine(1, summaryHtml)).toContain('80%'); }); @@ -54,7 +54,7 @@ describe('generateSummaryTabelHtml()', () => { }) }); - const summaryHtml = generateSummaryTableHtml(mockReport); + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, undefined); expect(getTableLine(1, summaryHtml)).toContain('8 / 10'); }); @@ -66,7 +66,7 @@ describe('generateSummaryTabelHtml()', () => { pct: 81, }) }); - const summaryHtml = generateSummaryTableHtml(mockReport, thresholds); + const summaryHtml = generateSummaryTableHtml(mockReport, thresholds, undefined); expect(getTableLine(1, summaryHtml)).toContain(icons.green); }); @@ -78,12 +78,12 @@ describe('generateSummaryTabelHtml()', () => { pct: 81, }) }); - const summaryHtml = generateSummaryTableHtml(mockReport, thresholds); + const summaryHtml = generateSummaryTableHtml(mockReport, thresholds, undefined); expect(getTableLine(1, summaryHtml)).toContain(icons.red); }); - it('if threshold is given, provides the threshold in the percentage column.', async (): Promise => { + it('if threshold is given, provides the threshold in the category column.', async (): Promise => { const thresholds: Thresholds = { lines: 100 }; const mockReport = createMockCoverageReport({ lines: createMockReportNumbers({ @@ -91,8 +91,59 @@ describe('generateSummaryTabelHtml()', () => { }) }); - const summaryHtml = generateSummaryTableHtml(mockReport, thresholds); - - expect(getTableLine(1, summaryHtml)).toContain('80% / 100%'); + const summaryHtml = generateSummaryTableHtml(mockReport, thresholds, undefined); + + expect(getTableLine(1, summaryHtml)).toContain('80% (🎯 100%)'); }); + + it('if compare report is given and coverage decreased, provides the difference in the percentage column.', async (): Promise => { + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 80, + }) + }); + const mockCompareReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 90, + }) + }); + + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, mockCompareReport); + + expect(getTableLine(1, summaryHtml)).toContain('80%
⬇️ -10.00%'); + }); + + it('if compare report is given and coverage increased, provides the difference in the percentage column.', async (): Promise => { + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 90, + }) + }); + const mockCompareReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 80, + }) + }); + + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, mockCompareReport); + + expect(getTableLine(1, summaryHtml)).toContain('90%
⬆️ +10.00%'); + }); + + it('if compare report is given and coverage stayed the same, provides the difference in the percentage column.', async (): Promise => { + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 90, + }) + }); + const mockCompareReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 90, + }) + }); + + const summaryHtml = generateSummaryTableHtml(mockReport, undefined, mockCompareReport); + + expect(getTableLine(1, summaryHtml)).toContain('90%
🟰 ±0%'); + }); }); diff --git a/src/report/generateSummaryTableHtml.ts b/src/report/generateSummaryTableHtml.ts new file mode 100644 index 0000000..c13e858 --- /dev/null +++ b/src/report/generateSummaryTableHtml.ts @@ -0,0 +1,88 @@ +import { icons } from '../icons'; +import { oneLine } from 'common-tags'; +import { Thresholds } from '../types/Threshold'; +import { CoverageReport, ReportNumbers } from '../types/JsonSummary'; + +function generateSummaryTableHtml( + jsonReport: CoverageReport, + thresholds: Thresholds = {}, + jsonCompareReport: CoverageReport | undefined + ): string { + return oneLine` + + + + + + + + + + + + ${generateTableRow({ reportNumbers: jsonReport.lines, category: 'Lines', threshold: thresholds.lines, reportCompareNumbers: jsonCompareReport?.lines })} + + + ${generateTableRow({ reportNumbers: jsonReport.statements, category: 'Statements', threshold: thresholds.statements, reportCompareNumbers: jsonCompareReport?.statements })} + + + ${generateTableRow({ reportNumbers: jsonReport.functions, category: 'Functions', threshold: thresholds.functions, reportCompareNumbers: jsonCompareReport?.functions })} + + + ${generateTableRow({ reportNumbers: jsonReport.branches, category: 'Branches', threshold: thresholds.branches, reportCompareNumbers: jsonCompareReport?.branches })} + + +
StatusCategoryPercentageCovered / Total
+ `; +} + +function generateTableRow({ + reportNumbers, + category, + threshold, + reportCompareNumbers +}: { + reportNumbers: ReportNumbers; + category: string; + threshold?: number; + reportCompareNumbers?: ReportNumbers; +}): string { + + let status = icons.blue; + let percent = `${reportNumbers.pct}%`; + + if(threshold) { + percent = `${percent} (${icons.target} ${threshold}%)`; + status = reportNumbers.pct >= threshold ? icons.green : icons.red; + } + + if(reportCompareNumbers) { + const percentDiff = reportNumbers.pct - reportCompareNumbers.pct; + const compareString = getCompareString(percentDiff); + percent = `${percent}
${compareString}`; + } + + return ` + ${status} + ${category} + ${percent} + ${reportNumbers.covered} / ${reportNumbers.total} + `; +} + +function getCompareString(percentDiff: number): string { + if(percentDiff === 0) { + return `${icons.equal} ±0%`; + } + + if(percentDiff > 0) { + return `${icons.increase} +${percentDiff.toFixed(2)}%`; + } + + // The - char is already included in a negative number + return `${icons.decrease} ${percentDiff.toFixed(2)}%`; +} + +export { + generateSummaryTableHtml +}; diff --git a/src/getUncoveredLinesFromStatements.test.ts b/src/report/getUncoveredLinesFromStatements.test.ts similarity index 97% rename from src/getUncoveredLinesFromStatements.test.ts rename to src/report/getUncoveredLinesFromStatements.test.ts index 9013212..fc07fd2 100644 --- a/src/getUncoveredLinesFromStatements.test.ts +++ b/src/report/getUncoveredLinesFromStatements.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect} from 'vitest'; import { getUncoveredLinesFromStatements } from './getUncoveredLinesFromStatements'; -import { StatementCoverageReport } from './types/JsonFinal'; +import { StatementCoverageReport } from '../types/JsonFinal'; describe('getUncoveredLinesFromStatements()', () => { it('returns a single line range for only one untested line.', () => { diff --git a/src/getUncoveredLinesFromStatements.ts b/src/report/getUncoveredLinesFromStatements.ts similarity index 92% rename from src/getUncoveredLinesFromStatements.ts rename to src/report/getUncoveredLinesFromStatements.ts index 6e2d60a..ce5a40b 100644 --- a/src/getUncoveredLinesFromStatements.ts +++ b/src/report/getUncoveredLinesFromStatements.ts @@ -1,4 +1,4 @@ -import { StatementCoverageReport } from './types/JsonFinal'; +import { StatementCoverageReport } from '../types/JsonFinal'; type LineRange = { start: number, diff --git a/test/exportTestTable.ts b/test/exportTestTable.ts new file mode 100644 index 0000000..9b2d17d --- /dev/null +++ b/test/exportTestTable.ts @@ -0,0 +1,31 @@ +import path from 'path'; +import { writeFile, mkdir } from 'fs/promises'; +import { parseVitestJsonSummary } from '../src/inputs/parseJsonReports'; +import { generateSummaryTableHtml } from '../src/report/generateSummaryTableHtml'; + +const basePath = path.join(__dirname, 'mockReports', 'coverage'); +const coveragePath = path.join(basePath, 'coverage-summary.json'); +const coverageComparePath = path.join(basePath, 'coverage-summary-compare.json'); + +const targetPath = path.join(__dirname, '..', 'tmp'); + + +async function generateMarkdown() { + // Parse the coverage reports + const coverageSummary = await parseVitestJsonSummary(coveragePath); + const coverageSummaryCompare = await parseVitestJsonSummary(coverageComparePath); + + // Generate the HTML table + const htmlTable = generateSummaryTableHtml(coverageSummary.total, { + branches: 60, + functions: 50, + lines: 40, + statements: 20, + }, coverageSummaryCompare.total); + + // Write the HTML into a markdown file + await mkdir(targetPath, { recursive: true }); + await writeFile(path.join(targetPath, 'coverage-summary.md'), htmlTable); +} + +generateMarkdown().catch(console.error); diff --git a/test/mockReports/coverage/coverage-summary-compare.json b/test/mockReports/coverage/coverage-summary-compare.json new file mode 100644 index 0000000..1d47fed --- /dev/null +++ b/test/mockReports/coverage/coverage-summary-compare.json @@ -0,0 +1,164 @@ +{ + "total": { + "lines": { + "total": 145, + "covered": 69, + "skipped": 0, + "pct": 47.58 + }, + "statements": { + "total": 150, + "covered": 74.4, + "skipped": 0, + "pct": 49.6 + }, + "functions": { + "total": 29, + "covered": 17.1, + "skipped": 0, + "pct": 58.96 + }, + "branches": { + "total": 58, + "covered": 20.7, + "skipped": 0, + "pct": 35.68 + }, + "branchesTrue": { + "total": 0, + "covered": 0, + "skipped": 0, + "pct": "Unknown" + } + }, + "/absolute/path/src/constants.js": { + "lines": { + "total": 1, + "covered": 1.15, + "skipped": 0, + "pct": 115 + }, + "functions": { + "total": 0, + "covered": 0, + "skipped": 0, + "pct": 95 + }, + "statements": { + "total": 1, + "covered": 1.2, + "skipped": 0, + "pct": 120 + }, + "branches": { + "total": 0, + "covered": 0, + "skipped": 0, + "pct": 90 + } + }, + "/absolute/path/src/format.js": { + "lines": { + "total": 33, + "covered": 27.6, + "skipped": 0, + "pct": 83.63 + }, + "functions": { + "total": 10, + "covered": 7.6, + "skipped": 0, + "pct": 76 + }, + "statements": { + "total": 33, + "covered": 28.8, + "skipped": 0, + "pct": 87.26 + }, + "branches": { + "total": 15, + "covered": 7.2, + "skipped": 0, + "pct": 48 + } + }, + "/absolute/path/src/index.js": { + "lines": { + "total": 69, + "covered": 0, + "skipped": 0, + "pct": 0 + }, + "functions": { + "total": 8, + "covered": 0, + "skipped": 0, + "pct": 0 + }, + "statements": { + "total": 72, + "covered": 0, + "skipped": 0, + "pct": 0 + }, + "branches": { + "total": 24, + "covered": 0, + "skipped": 0, + "pct": 0 + } + }, + "/absolute/path/src/parse.js": { + "lines": { + "total": 20, + "covered": 17.25, + "skipped": 0, + "pct": 86.25 + }, + "functions": { + "total": 3, + "covered": 1.9, + "skipped": 0, + "pct": 63.33 + }, + "statements": { + "total": 20, + "covered": 18, + "skipped": 0, + "pct": 90 + }, + "branches": { + "total": 5, + "covered": 2.7, + "skipped": 0, + "pct": 54 + } + }, + "/absolute/path/src/utils.js": { + "lines": { + "total": 22, + "covered": 23, + "skipped": 0, + "pct": 104.54 + }, + "functions": { + "total": 8, + "covered": 7.6, + "skipped": 0, + "pct": 95 + }, + "statements": { + "total": 24, + "covered": 26.4, + "skipped": 0, + "pct": 110 + }, + "branches": { + "total": 14, + "covered": 10.8, + "skipped": 0, + "pct": 77.14 + } + } +}