From 4f2bca0495f1ef278f12a36500711286a82206fd Mon Sep 17 00:00:00 2001 From: David Losert Date: Tue, 3 Jan 2023 09:13:08 +0100 Subject: [PATCH] test: Adds tests for FileCoverageHtml, creates mockFactories and refactors tests for SummaryTable (#15) * test: Adds tests for FileCoverageHtml, creates mockFactories and refactors tests for SummaryTable * chore: Removes non-required export --- .gitignore | 1 + src/generateFileCoverageHtml.test.ts | 56 +++++++++ src/generateSummaryTableHtml.test.ts | 129 +++++++++++---------- src/generateSummaryTableHtml.ts | 20 +--- src/index.ts | 4 +- src/testFolder/moreNesting/untestedFile.ts | 8 -- src/types/JsonFinal.ts | 4 +- src/types/JsonFinalMockFactory.ts | 47 ++++++++ src/types/JsonSummaryMockFactory.ts | 61 ++++++++++ test/queryHelper.ts | 14 +++ vite.config.js | 2 +- 11 files changed, 259 insertions(+), 87 deletions(-) create mode 100644 src/generateFileCoverageHtml.test.ts delete mode 100644 src/testFolder/moreNesting/untestedFile.ts create mode 100644 src/types/JsonFinalMockFactory.ts create mode 100644 src/types/JsonSummaryMockFactory.ts create mode 100644 test/queryHelper.ts diff --git a/.gitignore b/.gitignore index 2bdcf66..172bc4f 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,4 @@ typings/ .tern-port !test/mockReports/coverage +tmp diff --git a/src/generateFileCoverageHtml.test.ts b/src/generateFileCoverageHtml.test.ts new file mode 100644 index 0000000..29c6579 --- /dev/null +++ b/src/generateFileCoverageHtml.test.ts @@ -0,0 +1,56 @@ +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 { describe, it, expect } from 'vitest'; + +describe('generateFileCoverageHtml()', () => { + it('renders the statements, branches, functions and line coverage-percentage of a file.', () => { + const jsonSummary: JsonSummary = createMockJsonSummary({ + 'src/generateFileCoverageHtml.ts': { + statements: createMockReportNumbers({ pct: 70, }), + branches: createMockReportNumbers({ pct: 80, }), + functions: createMockReportNumbers({ pct: 90, }), + lines: createMockReportNumbers({ pct: 100, }), + }, + }); + + const html = generateFileCoverageHtml({ + jsonSummary, + jsonFinal: {} + }); + + const firstTableLine = getTableLine(1, html); + + expect(firstTableLine).toContain('70%'); + expect(firstTableLine).toContain('80%'); + expect(firstTableLine).toContain('90%'); + expect(firstTableLine).toContain('100%'); + }); + + it('renders the line-coverage in the same row as the coverage.', async (): Promise => { + const jsonSummary: JsonSummary = createMockJsonSummary({ + 'src/exampleFile.ts': createMockCoverageReport({ + statements: createMockReportNumbers({ pct: 70, }), + }), + }); + const jsonFinal: JsonFinal = { + ...createJsonFinalEntry('src/exampleFile.ts', [ + { line: 1, covered: false }, + { line: 2, covered: false } + ]), + }; + + const html = generateFileCoverageHtml({ + jsonSummary, + jsonFinal + }); + + const firstTableLine = getTableLine(1, html); + + expect(firstTableLine).toContain('70%'); + expect(firstTableLine).toContain('1-2'); + }); +}); diff --git a/src/generateSummaryTableHtml.test.ts b/src/generateSummaryTableHtml.test.ts index a86025f..f384670 100644 --- a/src/generateSummaryTableHtml.test.ts +++ b/src/generateSummaryTableHtml.test.ts @@ -1,89 +1,98 @@ -import { describe, it, expect } from 'vitest'; -import * as core from '@actions/core'; -import { generateSummaryTableData, TableData } from './generateSummaryTableHtml'; -import { CoverageReport } from './types/JsonSummary'; +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 { describe, it, expect } from 'vitest'; -describe('generateSummaryTabelHtml', () => { - const mockReport: CoverageReport = { - branches: { covered: 10, skipped: 8, pct: 100, total: 18 }, - functions: { covered: 0, skipped: 0, pct: 100, total: 0 }, - lines: { covered: 8, skipped: 0, pct: 80, total: 10 }, - statements: { covered: 0, skipped: 0, pct: 100, total: 0 } - } - - const stringifyTableData = (tableData: TableData) => { - return tableData; - } - +describe('generateSummaryTabelHtml()', () => { it('generates the headline', () => { - const data = generateSummaryTableData(mockReport); - const result = stringifyTableData(data); + const mockReport = createMockCoverageReport(); + const summaryHtml = generateSummaryTableHtml(mockReport); + const headline = getTableLine(0, summaryHtml); - expect(result).toContain('Status'); - expect(result).toContain('Category'); - expect(result).toContain('Percentage'); - expect(result).toContain('Covered / Total'); + expect(headline).toContain('Status'); + expect(headline).toContain('Category'); + expect(headline).toContain('Percentage'); + expect(headline).toContain('Covered / Total'); + }); + + it('generates all categories as rows', async (): Promise => { + const mockReport = createMockCoverageReport(); + const summaryHtml = generateSummaryTableHtml(mockReport); + + expect(getTableLine(1, summaryHtml)).toContain('Lines'); + expect(getTableLine(2, summaryHtml)).toContain('Statements'); + expect(getTableLine(3, summaryHtml)).toContain('Functions'); + expect(getTableLine(4, summaryHtml)).toContain('Branches'); }); + it('adds status blue-circle if no threshold provided.', async (): Promise => { - const tableData = generateSummaryTableData(mockReport); - const result = stringifyTableData(tableData); + const mockReport = createMockCoverageReport(); + const summaryHtml = generateSummaryTableHtml(mockReport); - expect(result).toContain(icons.blue); + expect(summaryHtml).toContain(icons.blue); }); - it('adds green-circle if percentage is below threshold.', async (): Promise => { - const data = generateSummaryTableData(mockReport, { - lines: 80 + + it('adds the percentage with a %-sign.', async (): Promise => { + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ pct: 80 }) }); - const result = stringifyTableData(data); + const summaryHtml = generateSummaryTableHtml(mockReport); - expect(result).toContain(icons.green); + expect(getTableLine(1, summaryHtml)).toContain('80%'); }); - it('adds red-circle if percentage is below threshold.', async (): Promise => { - const data = generateSummaryTableData(mockReport, { - lines: 100 + it('shows the covered / total numbers.', async (): Promise => { + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + covered: 8, + total: 10, + }) }); - - const result = stringifyTableData(data); - - expect(result).toContain(icons.red); - }); - - it('shows all categories', async (): Promise => { - const data = generateSummaryTableData(mockReport); - const result = stringifyTableData(data); - expect(result).toContain('Lines'); - expect(result).toContain('Statements'); - expect(result).toContain('Functions'); - expect(result).toContain('Branches'); + const summaryHtml = generateSummaryTableHtml(mockReport); + + expect(getTableLine(1, summaryHtml)).toContain('8 / 10'); }); - it('adds the percentage with a %-sign.', async (): Promise => { - const data = generateSummaryTableData(mockReport); - const result = stringifyTableData(data); + it('adds green-circle if percentage is above threshold.', async (): Promise => { + const thresholds: Thresholds = { lines: 80 }; + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 81, + }) + }); + const summaryHtml = generateSummaryTableHtml(mockReport, thresholds); - expect(result).toContain('80%'); + expect(getTableLine(1, summaryHtml)).toContain(icons.green); }); - it('shows the covered / total numbers.', async (): Promise => { - const data = generateSummaryTableData(mockReport); - const result = stringifyTableData(data); + it('adds red-circle if percentage is below threshold.', async (): Promise => { + const thresholds: Thresholds = { lines: 100 }; + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 81, + }) + }); + const summaryHtml = generateSummaryTableHtml(mockReport, thresholds); - expect(result).toContain('8 / 10'); + expect(getTableLine(1, summaryHtml)).toContain(icons.red); }); - + it('if threshold is given, provides the threshold in the percentage column.', async (): Promise => { - const data = generateSummaryTableData(mockReport, { - lines: 100 + const thresholds: Thresholds = { lines: 100 }; + const mockReport = createMockCoverageReport({ + lines: createMockReportNumbers({ + pct: 80, + }) }); + + const summaryHtml = generateSummaryTableHtml(mockReport, thresholds); - const result = stringifyTableData(data); - - expect(result).toContain('80% / 100%'); + expect(getTableLine(1, summaryHtml)).toContain('80% / 100%'); }); }); diff --git a/src/generateSummaryTableHtml.ts b/src/generateSummaryTableHtml.ts index 23d0964..3525180 100644 --- a/src/generateSummaryTableHtml.ts +++ b/src/generateSummaryTableHtml.ts @@ -1,11 +1,7 @@ -import { CoverageReport, JsonSummary, ReportNumbers } from './types/JsonSummary'; -import { Thresholds } from './types/Threshold'; -import core from '@actions/core'; -import { oneLine } from 'common-tags'; import { icons } from './icons'; - -type TableData = string; - +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 => { @@ -26,7 +22,7 @@ const generateTableRow = ({ reportNumbers, category, threshold }: { reportNumber } -const generateSummaryTableData = (jsonReport: CoverageReport, thresholds: Thresholds = {}): TableData => { +const generateSummaryTableHtml = (jsonReport: CoverageReport, thresholds: Thresholds = {}): string => { return oneLine` @@ -53,14 +49,8 @@ const generateSummaryTableData = (jsonReport: CoverageReport, thresholds: Thresh
` - } export { - generateSummaryTableData, - generateTableRow -}; - -export type { - TableData + generateSummaryTableHtml }; diff --git a/src/index.ts b/src/index.ts index ee4018c..64521ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { generateSummaryTableData } from './generateSummaryTableHtml.js'; +import { generateSummaryTableHtml } from './generateSummaryTableHtml.js'; import path from 'node:path'; import { parseVitestJsonFinal, parseVitestJsonSummary } from './parseJsonReports.js'; import { writeSummaryToPR } from './writeSummaryToPR.js'; @@ -18,7 +18,7 @@ const run = async () => { const jsonFinal = await parseVitestJsonFinal(jsonFinalPath); const thresholds = await parseCoverageThresholds(viteConfigPath); - const tableData = generateSummaryTableData(jsonSummary.total, thresholds); + const tableData = generateSummaryTableHtml(jsonSummary.total, thresholds); const fileTable = generateFileCoverageHtml({ jsonSummary, jsonFinal }); diff --git a/src/testFolder/moreNesting/untestedFile.ts b/src/testFolder/moreNesting/untestedFile.ts deleted file mode 100644 index 45aa337..0000000 --- a/src/testFolder/moreNesting/untestedFile.ts +++ /dev/null @@ -1,8 +0,0 @@ -const thisIsNotTeste = (...params: any[]) => { - // calculate the sum of all parameters - return params.reduce((a, b) => a + b, 0); -} - -export { - thisIsNotTeste -}; diff --git a/src/types/JsonFinal.ts b/src/types/JsonFinal.ts index 6c64ff3..d76d53d 100644 --- a/src/types/JsonFinal.ts +++ b/src/types/JsonFinal.ts @@ -31,5 +31,7 @@ type JsonFinal = { export type { JsonFinal, - StatementCoverageReport + FileCoverageReport, + StatementCoverageReport, + StatementMap }; diff --git a/src/types/JsonFinalMockFactory.ts b/src/types/JsonFinalMockFactory.ts new file mode 100644 index 0000000..9061e43 --- /dev/null +++ b/src/types/JsonFinalMockFactory.ts @@ -0,0 +1,47 @@ +import { JsonFinal, StatementCoverageReport, StatementMap } from './JsonFinal'; + +type LineConfig = { line: number, covered: boolean }; +const createJsonFinalEntry = (fileName: string, lineConfigs: LineConfig[]): JsonFinal => { + const statementCoverageReport: StatementCoverageReport = { + statementMap: lineConfigs.reduce((obj, lineConfig) => ({ + ...obj, + [lineConfig.line - 1]: { + start: { + line: lineConfig.line, + column: 0 + }, + end: { + line: lineConfig.line, + column: 0 + } + } + }), {}), + s: lineConfigs.reduce((obj, lineConfig) => ({ + ...obj, + [lineConfig.line - 1]: lineConfig.covered ? 1 : 0 + }), {}) + }; + + return { + [fileName]: { + path: fileName, + all: false, + ...statementCoverageReport + } + } +} + +const defaultJsonFinal: JsonFinal = { + ...createJsonFinalEntry('src/exampleFile.ts', [{line: 1, covered: false}]) +}; + + +const createTestJsonFinal = (overwrites: Partial = {}): JsonFinal => ({ + ...defaultJsonFinal, + ...overwrites +} as JsonFinal); + +export { + createTestJsonFinal, + createJsonFinalEntry +}; diff --git a/src/types/JsonSummaryMockFactory.ts b/src/types/JsonSummaryMockFactory.ts new file mode 100644 index 0000000..5cb4ac2 --- /dev/null +++ b/src/types/JsonSummaryMockFactory.ts @@ -0,0 +1,61 @@ +import { CoverageReport, JsonSummary, ReportNumbers } from './JsonSummary'; + +const defaultReportNumbers: ReportNumbers = { + total: 100, + covered: 5, + pct: 5, + skipped: 0, +} + +const createMockReportNumbers = (overwrites: Partial = {}): ReportNumbers => ({ + ...defaultReportNumbers, + ...overwrites +}); + +const defaultReport: CoverageReport = { + lines: createMockReportNumbers(), + statements: createMockReportNumbers(), + functions: createMockReportNumbers(), + branches: createMockReportNumbers(), +} + +const createMockCoverageReport = (overwrites: Partial = {}): CoverageReport => ({ + ...defaultReport, + ...overwrites, +} as CoverageReport); + +const defaultJsonSummary: JsonSummary = { + total: createMockCoverageReport({ + statements: createMockReportNumbers({ + total: 100, + covered: 10, + pct: 10, + }), + branches: createMockReportNumbers({ + total: 100, + covered: 20, + pct: 20, + }), + functions: createMockReportNumbers({ + total: 100, + covered: 30, + pct: 30, + }), + lines: createMockReportNumbers({ + total: 100, + covered: 40, + pct: 40, + }), + }) +}; + +const createMockJsonSummary = (overwrites: Partial = {}): JsonSummary => ({ + ...defaultJsonSummary, + ...overwrites, +} as JsonSummary); + +export { + createMockJsonSummary, + createMockReportNumbers, + createMockCoverageReport +}; diff --git a/test/queryHelper.ts b/test/queryHelper.ts new file mode 100644 index 0000000..1995c7f --- /dev/null +++ b/test/queryHelper.ts @@ -0,0 +1,14 @@ +const tableRowRegexp = /[^]+?<\/tr>/g; +function getTableLine(line: number, html: string) { + const table = html.match(/.*<\/table>/); + if(!table) { + throw new Error('No table found'); + } + const tableLine = table[0].match(tableRowRegexp); + if(!tableLine) { + throw new Error('No table line found'); + } + return tableLine[line]; +}; + +export { getTableLine }; diff --git a/vite.config.js b/vite.config.js index e962b63..79104d7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -6,7 +6,7 @@ export default defineConfig({ all: true, reporter: ['text', 'json-summary', 'json'], include: ['src'], - exclude: ['src/types'], + exclude: ['src/types', '**/*.test.ts'], } } });