Skip to content

Commit d7a086a

Browse files
9aoyCopilot
andauthored
feat: support coverage.reportsDirectory option (#557)
Co-authored-by: Copilot <[email protected]>
1 parent 56e9bde commit d7a086a

File tree

10 files changed

+133
-14
lines changed

10 files changed

+133
-14
lines changed

e2e/projects/coverage.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { dirname, join } from 'node:path';
2+
import { fileURLToPath } from 'node:url';
3+
import { describe, expect, it } from '@rstest/core';
4+
import fs from 'fs-extra';
5+
import { runRstestCli } from '../scripts';
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = dirname(__filename);
9+
10+
describe('test projects coverage', () => {
11+
it('should run projects correctly with coverage', async () => {
12+
const { cli, expectExecSuccess } = await runRstestCli({
13+
command: 'rstest',
14+
args: ['run', '--globals', '-c', 'rstest.coverage.config.ts'],
15+
options: {
16+
nodeOptions: {
17+
cwd: join(__dirname, 'fixtures'),
18+
},
19+
},
20+
});
21+
22+
await expectExecSuccess();
23+
const logs = cli.stdout.split('\n').filter(Boolean);
24+
25+
expect(
26+
logs.find(
27+
(log) =>
28+
log.includes('All files') &&
29+
log.replaceAll(' ', '').includes('100|100|100|100'),
30+
),
31+
).toBeTruthy();
32+
33+
expect(
34+
logs.find(
35+
(log) =>
36+
log.includes('client/test') &&
37+
log.replaceAll(' ', '').includes('100|100|100|100'),
38+
),
39+
).toBeTruthy();
40+
41+
expect(
42+
logs.find(
43+
(log) =>
44+
log.includes('node') &&
45+
log.replaceAll(' ', '').includes('100|100|100|100'),
46+
),
47+
).toBeTruthy();
48+
49+
expect(
50+
fs.existsSync(join(__dirname, 'fixtures/coverage/index.html')),
51+
).toBeTruthy();
52+
});
53+
});

e2e/projects/fixtures/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"private": true,
3+
"name": "@rstest/tests-projects",
4+
"sideEffects": true,
5+
"version": "1.0.0",
6+
"devDependencies": {
7+
"@rstest/core": "workspace:*",
8+
"@rstest/coverage-istanbul": "workspace:*"
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { defineConfig } from '@rstest/core';
2+
3+
export default defineConfig({
4+
projects: ['packages/*'],
5+
globals: true,
6+
coverage: {
7+
enabled: true,
8+
},
9+
setupFiles: ['./setup.ts'],
10+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { defineConfig } from '@rstest/core';
2+
3+
export default defineConfig({
4+
coverage: {
5+
enabled: true,
6+
provider: 'istanbul',
7+
reportsDirectory: 'test-temp-coverage',
8+
},
9+
});

e2e/test-coverage/index.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,25 @@ it('coverage-istanbul with custom options', async () => {
104104
fs.existsSync(join(__dirname, 'fixtures/coverage/index.html')),
105105
).toBeTruthy();
106106
});
107+
108+
it('coverage-istanbul with custom reportsDirectory', async () => {
109+
const { expectExecSuccess, expectLog, cli } = await runRstestCli({
110+
command: 'rstest',
111+
args: ['run', '-c', 'rstest.reportsDirectory.config.ts'],
112+
options: {
113+
nodeOptions: {
114+
cwd: join(__dirname, 'fixtures'),
115+
},
116+
},
117+
});
118+
119+
await expectExecSuccess();
120+
121+
const logs = cli.stdout.split('\n').filter(Boolean);
122+
123+
expectLog('Coverage enabled with istanbul', logs);
124+
125+
expect(
126+
fs.existsSync(join(__dirname, 'fixtures/test-temp-coverage/index.html')),
127+
).toBeTruthy();
128+
});

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"@sinonjs/fake-timers": "^14.0.0",
7070
"@types/babel__code-frame": "^7.0.6",
7171
"@types/istanbul-reports": "^3.0.4",
72+
"@types/istanbul-lib-coverage": "^2.0.6",
7273
"@types/jsdom": "^21.1.7",
7374
"@types/sinonjs__fake-timers": "^8.1.5",
7475
"@types/source-map-support": "^0.5.10",

packages/core/src/config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
loadConfig as loadRsbuildConfig,
55
mergeRsbuildConfig,
66
} from '@rsbuild/core';
7-
import { dirname, isAbsolute, join } from 'pathe';
7+
import { dirname, isAbsolute, join, resolve } from 'pathe';
88
import type { NormalizedConfig, RstestConfig } from './types';
99
import {
1010
color,
@@ -115,6 +115,7 @@ const createDefaultConfig = (): NormalizedConfig => ({
115115
enabled: false,
116116
provider: 'istanbul',
117117
reporters: ['text', 'html', 'clover', 'json'],
118+
reportsDirectory: './coverage',
118119
},
119120
});
120121

@@ -131,6 +132,11 @@ export const withDefaultConfig = (config: RstestConfig): NormalizedConfig => {
131132
merged.coverage ??= {};
132133
merged.coverage.reporters =
133134
config.coverage?.reporters ?? merged.coverage?.reporters;
135+
const reportsDirectory = merged.coverage.reportsDirectory!;
136+
merged.coverage.reportsDirectory = isAbsolute(reportsDirectory)
137+
? reportsDirectory
138+
: resolve(merged.root!, reportsDirectory);
139+
134140
merged.pool =
135141
typeof config.pool === 'string'
136142
? {

packages/core/src/types/coverage.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CoverageMap } from 'istanbul-lib-coverage';
12
import type { ReportOptions } from 'istanbul-reports';
23

34
type ReportWithOptions<Name extends keyof ReportOptions = keyof ReportOptions> =
@@ -24,17 +25,17 @@ export type CoverageOptions = {
2425
*/
2526
reporters?: (keyof ReportOptions | ReportWithOptions)[];
2627

28+
/**
29+
* The directory to store coverage reports.
30+
* @default './coverage'
31+
*/
32+
reportsDirectory?: string;
33+
2734
// TODO: support clean
2835
};
2936

3037
export type NormalizedCoverageOptions = Required<CoverageOptions>;
3138

32-
interface CoverageMap {
33-
files(): string[];
34-
merge(other: any): void;
35-
toJSON(): any;
36-
}
37-
3839
export declare class CoverageProvider {
3940
constructor(options: CoverageOptions);
4041
/**

packages/coverage-istanbul/src/provider.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@ import type {
22
NormalizedCoverageOptions,
33
CoverageProvider as RstestCoverageProvider,
44
} from '@rstest/core';
5+
import type { CoverageMap } from 'istanbul-lib-coverage';
56
import istanbulLibCoverage from 'istanbul-lib-coverage';
67
import { createContext } from 'istanbul-lib-report';
78
import reports from 'istanbul-reports';
89

910
const { createCoverageMap } = istanbulLibCoverage;
1011

11-
interface CoverageMap {
12-
files(): string[];
13-
merge(other: any): void;
14-
toJSON(): any;
15-
}
16-
1712
// Global type declaration for coverage
1813
declare global {
1914
var __coverage__: any;
@@ -63,7 +58,7 @@ export class CoverageProvider implements RstestCoverageProvider {
6358

6459
try {
6560
const context = createContext({
66-
dir: 'coverage',
61+
dir: this.options.reportsDirectory,
6762
defaultSummarizer: 'nested',
6863
coverageMap: createCoverageMap(coverageMap.toJSON()),
6964
});

pnpm-lock.yaml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)