Skip to content

Commit f0b5460

Browse files
committed
feat(plugin-coverage): allow passing results as strings
1 parent b3c6a3d commit f0b5460

File tree

10 files changed

+54
-47
lines changed

10 files changed

+54
-47
lines changed

e2e/cli-e2e/mocks/fixtures/code-pushup.config.coverage.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,7 @@ export default {
2525
],
2626
plugins: [
2727
await coveragePlugin({
28-
reports: [
29-
{
30-
resultsPath: join('e2e', 'cli-e2e', 'mocks', 'fixtures', 'lcov.info'),
31-
pathToProject: join('packages', 'cli'),
32-
},
33-
],
28+
reports: [join('e2e', 'cli-e2e', 'mocks', 'fixtures', 'lcov.info')],
3429
}),
3530
],
3631
} satisfies CoreConfig;

e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap

+8-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
2828
"message": "Function formatReportScore is not called in any test case.",
2929
"severity": "error",
3030
"source": {
31-
"file": "packages/cli/src/lib/partly-covered/utils.ts",
31+
"file": "src/lib/partly-covered/utils.ts",
3232
"position": {
3333
"startLine": 2,
3434
},
@@ -38,7 +38,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
3838
"message": "Function sortReport is not called in any test case.",
3939
"severity": "error",
4040
"source": {
41-
"file": "packages/cli/src/lib/not-covered/sorting.ts",
41+
"file": "src/lib/not-covered/sorting.ts",
4242
"position": {
4343
"startLine": 1,
4444
},
@@ -60,7 +60,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
6060
"message": "2nd branch is not taken in any test case.",
6161
"severity": "error",
6262
"source": {
63-
"file": "packages/cli/src/lib/partly-covered/utils.ts",
63+
"file": "src/lib/partly-covered/utils.ts",
6464
"position": {
6565
"startLine": 6,
6666
},
@@ -70,7 +70,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
7070
"message": "2nd branch is not taken in any test case.",
7171
"severity": "error",
7272
"source": {
73-
"file": "packages/cli/src/lib/partly-covered/utils.ts",
73+
"file": "src/lib/partly-covered/utils.ts",
7474
"position": {
7575
"startLine": 10,
7676
},
@@ -80,7 +80,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
8080
"message": "1st branch is not taken in any test case.",
8181
"severity": "error",
8282
"source": {
83-
"file": "packages/cli/src/lib/not-covered/sorting.ts",
83+
"file": "src/lib/not-covered/sorting.ts",
8484
"position": {
8585
"startLine": 7,
8686
},
@@ -90,7 +90,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
9090
"message": "2nd branch is not taken in any test case.",
9191
"severity": "error",
9292
"source": {
93-
"file": "packages/cli/src/lib/not-covered/sorting.ts",
93+
"file": "src/lib/not-covered/sorting.ts",
9494
"position": {
9595
"startLine": 7,
9696
},
@@ -112,7 +112,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
112112
"message": "Lines 7-9 are not covered in any test case.",
113113
"severity": "warning",
114114
"source": {
115-
"file": "packages/cli/src/lib/partly-covered/utils.ts",
115+
"file": "src/lib/partly-covered/utils.ts",
116116
"position": {
117117
"endLine": 9,
118118
"startLine": 7,
@@ -123,7 +123,7 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
123123
"message": "Lines 1-5 are not covered in any test case.",
124124
"severity": "warning",
125125
"source": {
126-
"file": "packages/cli/src/lib/not-covered/sorting.ts",
126+
"file": "src/lib/not-covered/sorting.ts",
127127
"position": {
128128
"endLine": 5,
129129
"startLine": 1,

packages/plugin-coverage/README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Measured coverage types are mapped to Code PushUp audits in the following way
3636
plugins: [
3737
// ...
3838
await coveragePlugin({
39-
reports: [{ resultsPath: 'coverage/lcov.info' }],
39+
reports: ['coverage/lcov.info'],
4040
coverageToolCommand: {
4141
command: 'npx',
4242
args: ['jest', '--coverage', '--coverageReporters=lcov'],
@@ -119,8 +119,9 @@ It recognises the following entities:
119119
The plugin accepts the following parameters:
120120

121121
- `coverageTypes`: An array of types of coverage that you wish to track. Supported values: `function`, `branch`, `line`. Defaults to all available types.
122-
- `reports`: Array of information about files with code coverage results - paths to results, path to project root the results belong to. LCOV format is supported for now.
123-
- If you have an Nx monorepo, you can adjust our helper function `getNxCoveragePaths` to get the path information automatically.
122+
- `reports`: Array of information about files with code coverage results. LCOV format is supported for now.
123+
- For a single project, providing paths to results as strings is enough.
124+
- If you have an Nx monorepo, both path to results (`resultsPath`) and path from the root to project the results belong to (`pathToProject`) need to be provided for the LCOV format. You can adjust our helper function `getNxCoveragePaths` to get the path information automatically.
124125
- (optional) `coverageToolCommand`: If you wish to run your coverage tool to generate the results first, you may define it here.
125126
- (optional) `perfectScoreThreshold`: If your coverage goal is not 100%, you may define it here in range 0-1. Any score above the defined threshold will be given the perfect score. The value will stay unaffected.
126127

packages/plugin-coverage/src/lib/config.ts

+18-7
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,26 @@ import { z } from 'zod';
33
export const coverageTypeSchema = z.enum(['function', 'branch', 'line']);
44
export type CoverageType = z.infer<typeof coverageTypeSchema>;
55

6-
export const coverageResultSchema = z.object({
7-
resultsPath: z.string().includes('lcov'),
8-
pathToProject: z
6+
export const coverageResultSchema = z.union([
7+
z.object({
8+
resultsPath: z
9+
.string({
10+
description: 'Path to coverage results for Nx setup.',
11+
})
12+
.includes('lcov'),
13+
pathToProject: z
14+
.string({
15+
description:
16+
'Path from workspace root to project root. Necessary for LCOV reports which provide a relative path.',
17+
})
18+
.optional(),
19+
}),
20+
z
921
.string({
10-
description:
11-
'Path from workspace root to project root. Necessary for LCOV reports.',
22+
description: 'Path to coverage results for a single project setup.',
1223
})
13-
.optional(),
14-
});
24+
.includes('lcov'),
25+
]);
1526
export type CoverageResult = z.infer<typeof coverageResultSchema>;
1627

1728
export const coveragePluginConfigSchema = z.object({

packages/plugin-coverage/src/lib/config.unit.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ describe('coveragePluginConfigSchema', () => {
2828
it('accepts a minimal code coverage configuration', () => {
2929
expect(() =>
3030
coveragePluginConfigSchema.parse({
31-
reports: [{ resultsPath: 'coverage/cli/lcov.info' }],
31+
reports: ['coverage/cli/lcov.info'],
3232
} satisfies CoveragePluginConfig),
3333
).not.toThrow();
3434
});
3535

3636
it('replaces undefined coverage with all available types', () => {
3737
const config = {
38-
reports: [{ resultsPath: 'coverage/cli/lcov.info' }],
38+
reports: ['coverage/cli/lcov.info'],
3939
} satisfies CoveragePluginConfig;
4040
expect(() => coveragePluginConfigSchema.parse(config)).not.toThrow();
4141

@@ -51,7 +51,7 @@ describe('coveragePluginConfigSchema', () => {
5151
expect(() =>
5252
coveragePluginConfigSchema.parse({
5353
coverageTypes: [],
54-
reports: [{ resultsPath: 'coverage/cli/lcov.info' }],
54+
reports: ['coverage/cli/lcov.info'],
5555
} satisfies CoveragePluginConfig),
5656
).toThrow('too_small');
5757
});
@@ -69,7 +69,7 @@ describe('coveragePluginConfigSchema', () => {
6969
expect(() =>
7070
coveragePluginConfigSchema.parse({
7171
coverageTypes: ['line'],
72-
reports: [{ resultsPath: 'coverage/cli/coverage-final.json' }],
72+
reports: ['coverage/cli/coverage-final.json'],
7373
} satisfies CoveragePluginConfig),
7474
).toThrow(/Invalid input: must include.+lcov/);
7575
});
@@ -90,7 +90,7 @@ describe('coveragePluginConfigSchema', () => {
9090
expect(() =>
9191
coveragePluginConfigSchema.parse({
9292
coverageTypes: ['line'],
93-
reports: [{ resultsPath: 'coverage/cli/lcov.info' }],
93+
reports: ['coverage/cli/lcov.info'],
9494
perfectScoreThreshold: 1.1,
9595
} satisfies CoveragePluginConfig),
9696
).toThrow('too_big');

packages/plugin-coverage/src/lib/coverage-plugin.unit.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe('coveragePlugin', () => {
2222
await expect(
2323
coveragePlugin({
2424
coverageTypes: ['function'],
25-
reports: [{ resultsPath: LCOV_PATH }],
25+
reports: [LCOV_PATH],
2626
}),
2727
).resolves.toStrictEqual(
2828
expect.objectContaining({
@@ -39,7 +39,7 @@ describe('coveragePlugin', () => {
3939
await expect(
4040
coveragePlugin({
4141
coverageTypes: ['function', 'branch'],
42-
reports: [{ resultsPath: LCOV_PATH }],
42+
reports: [LCOV_PATH],
4343
}),
4444
).resolves.toStrictEqual(
4545
expect.objectContaining({

packages/plugin-coverage/src/lib/runner/lcov/__snapshots__/lcov-runner.integration.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`lcovResultsToAuditOutputs > should correctly convert lcov results to AuditOutputs 1`] = `
3+
exports[`lcovResultsToAuditOutputs > should correctly convert lcov results to AuditOutputs and prepend project paths 1`] = `
44
[
55
{
66
"details": {

packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.integration.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { describe, it } from 'vitest';
44
import { lcovResultsToAuditOutputs } from './lcov-runner';
55

66
describe('lcovResultsToAuditOutputs', () => {
7-
it('should correctly convert lcov results to AuditOutputs', async () => {
7+
it('should correctly convert lcov results to AuditOutputs and prepend project paths', async () => {
88
/**
99
* The stats passed in the fixture are as follows
1010
* Functions: 2 found, 2 covered (100% coverage)

packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,14 @@ async function parseLcovFiles(
5353
): Promise<LCOVRecord[]> {
5454
const parsedResults = await Promise.all(
5555
results.map(async result => {
56-
const lcovFileContent = await readTextFile(result.resultsPath);
56+
const resultsPath =
57+
typeof result === 'string' ? result : result.resultsPath;
58+
const lcovFileContent = await readTextFile(resultsPath);
5759
const parsedRecords = parseLcov(toUnixNewlines(lcovFileContent));
5860
return parsedRecords.map<LCOVRecord>(record => ({
5961
...record,
6062
file:
61-
result.pathToProject == null
63+
typeof result === 'string' || result.pathToProject == null
6264
? record.file
6365
: join(result.pathToProject, record.file),
6466
}));

packages/plugin-coverage/src/lib/runner/runner.integration.test.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { PLUGIN_CONFIG_PATH, RUNNER_OUTPUT_PATH, WORKDIR } from './constants';
1111
describe('createRunnerConfig', () => {
1212
it('should create a valid runner config', async () => {
1313
const runnerConfig = await createRunnerConfig('executeRunner.ts', {
14-
reports: [{ resultsPath: 'coverage/lcov.info' }],
14+
reports: ['coverage/lcov.info'],
1515
coverageTypes: ['branch'],
1616
perfectScoreThreshold: 85,
1717
});
@@ -28,7 +28,7 @@ describe('createRunnerConfig', () => {
2828

2929
const pluginConfig: FinalCoveragePluginConfig = {
3030
coverageTypes: ['line'],
31-
reports: [{ resultsPath: 'coverage/lcov.info' }],
31+
reports: ['coverage/lcov.info'],
3232
coverageToolCommand: { command: 'npm', args: ['run', 'test'] },
3333
perfectScoreThreshold: 85,
3434
};
@@ -46,16 +46,14 @@ describe('executeRunner', () => {
4646
it('should successfully execute runner', async () => {
4747
const config: FinalCoveragePluginConfig = {
4848
reports: [
49-
{
50-
resultsPath: join(
51-
fileURLToPath(dirname(import.meta.url)),
52-
'..',
53-
'..',
54-
'..',
55-
'mocks',
56-
'single-record-lcov.info',
57-
),
58-
},
49+
join(
50+
fileURLToPath(dirname(import.meta.url)),
51+
'..',
52+
'..',
53+
'..',
54+
'mocks',
55+
'single-record-lcov.info',
56+
),
5957
],
6058
coverageTypes: ['line'],
6159
};

0 commit comments

Comments
 (0)