Skip to content

Commit 7fc7c2e

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat--plugin-doc-coverage
2 parents 1107ae4 + 4777a83 commit 7fc7c2e

File tree

14 files changed

+352
-12
lines changed

14 files changed

+352
-12
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Plugin request
2+
description: Add a request for a new plugin
3+
title: 'Plugin request'
4+
body:
5+
- type: textarea
6+
id: metric
7+
attributes:
8+
label: Metric
9+
description: Elaborate on the specific metric the plugin will measure.
10+
placeholder: e.g. Code coverage of functions, branches and lines.
11+
validations:
12+
required: true
13+
- type: markdown
14+
attributes:
15+
value: Please provide a concise set of requirements, so that we can process your request as soon as possible.
16+
- type: textarea
17+
id: user-story
18+
attributes:
19+
label: User story
20+
description: Here you can phrase your request in a user story format which highlights the added value of the requested plugin.
21+
placeholder: e.g. As a Code PushUp user, I want to <request>, so that <added value>.
22+
validations:
23+
required: true
24+
- type: textarea
25+
id: dependencies
26+
attributes:
27+
label: Dependencies
28+
description: List all added dependencies needed for the plugin (dev-dependencies excluded)
29+
placeholder: e.g. - [ts-morph npm package](https://www.npmjs.com/package/ts-morph)
30+
validations:
31+
required: false
32+
- type: textarea
33+
id: acceptance-criteria
34+
attributes:
35+
label: Acceptance criteria
36+
description: Please list a set of criteria to help us determine whether the scope of the plugin was fully addressed.
37+
placeholder: |
38+
For example:
39+
- [ ] All packages have a comprehensive documentation in place.
40+
- [ ] All unit, integration and e2e tests for the plugin.
41+
- [ ] Cross references to relevant models or files are added as links.
42+
validations:
43+
required: true
44+
- type: textarea
45+
id: implementation-details
46+
attributes:
47+
label: Implementation details
48+
description: If there are any implementation details you would want to point out, feel free to do so here.
49+
placeholder: e.g. A link to a 3rd-party library, relevant article, expected flow details, wireframes highlighting the change or other.

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('CLI collect', () => {
3838
});
3939

4040
it('should create report.md', async () => {
41-
const { code, stderr } = await executeProcess({
41+
const { code } = await executeProcess({
4242
command: 'npx',
4343
args: [
4444
'@code-pushup/cli',
@@ -50,7 +50,6 @@ describe('CLI collect', () => {
5050
});
5151

5252
expect(code).toBe(0);
53-
expect(stderr).toBe('');
5453

5554
const md = await readTextFile(path.join(dummyOutputDir, 'report.md'));
5655

@@ -60,14 +59,13 @@ describe('CLI collect', () => {
6059
});
6160

6261
it('should print report summary to stdout', async () => {
63-
const { code, stdout, stderr } = await executeProcess({
62+
const { code, stdout } = await executeProcess({
6463
command: 'npx',
6564
args: ['@code-pushup/cli', '--no-progress', 'collect'],
6665
cwd: dummyDir,
6766
});
6867

6968
expect(code).toBe(0);
70-
expect(stderr).toBe('');
7169

7270
expect(stdout).toContain('Code PushUp Report');
7371
expect(stdout).not.toContain('Generated reports');

e2e/cli-e2e/tests/help.e2e.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ describe('CLI help', () => {
1010
const envRoot = path.join(E2E_ENVIRONMENTS_DIR, nxTargetProject());
1111

1212
it('should print help with help command', async () => {
13-
const { code, stdout, stderr } = await executeProcess({
13+
const { code, stdout } = await executeProcess({
1414
command: 'npx',
1515
args: ['@code-pushup/cli', 'help'],
1616
cwd: envRoot,
1717
});
1818
expect(code).toBe(0);
19-
expect(stderr).toBe('');
2019
expect(removeColorCodes(stdout)).toMatchSnapshot();
2120
});
2221

e2e/create-cli-e2e/tests/init.e2e.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import { executeProcess, readJsonFile, readTextFile } from '@code-pushup/utils';
1313
const fakeCacheFolderName = () =>
1414
`fake-cache-${new Date().toISOString().replace(/[:.]/g, '-')}`;
1515

16-
describe('create-cli-init', () => {
16+
/* after a new release of the nx-verdaccio plugin we can enable the test again. For now, it is too flaky to be productive. (5.jan.2025) */
17+
describe.todo('create-cli-init', () => {
1718
const workspaceRoot = path.join(E2E_ENVIRONMENTS_DIR, nxTargetProject());
1819
const testFileDir = path.join(workspaceRoot, TEST_OUTPUT_DIR, 'init');
1920

e2e/plugin-eslint-e2e/tests/collect.e2e.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,13 @@ describe('PLUGIN collect report with eslint-plugin NPM package', () => {
4747
});
4848

4949
it('should run ESLint plugin for flat config and create report.json', async () => {
50-
const { code, stderr } = await executeProcess({
50+
const { code } = await executeProcess({
5151
command: 'npx',
5252
args: ['@code-pushup/cli', 'collect', '--no-progress'],
5353
cwd: flatConfigDir,
5454
});
5555

5656
expect(code).toBe(0);
57-
expect(stderr).toBe('');
5857

5958
const report = await readJsonFile(
6059
path.join(flatConfigOutputDir, 'report.json'),
@@ -65,15 +64,14 @@ describe('PLUGIN collect report with eslint-plugin NPM package', () => {
6564
});
6665

6766
it('should run ESLint plugin for legacy config and create report.json', async () => {
68-
const { code, stderr } = await executeProcess({
67+
const { code } = await executeProcess({
6968
command: 'npx',
7069
args: ['@code-pushup/cli', 'collect', '--no-progress'],
7170
cwd: legacyConfigDir,
7271
env: { ...process.env, ESLINT_USE_FLAT_CONFIG: 'false' },
7372
});
7473

7574
expect(code).toBe(0);
76-
expect(stderr).toBe('');
7775

7876
const report = await readJsonFile(
7977
path.join(legacyConfigOutputDir, 'report.json'),

testing/test-setup/project.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
"assets": ["testing/test-setup/*.md"]
1515
}
1616
},
17+
"unit-test": {
18+
"executor": "@nx/vite:test",
19+
"options": {
20+
"configFile": "testing/test-setup/vite.config.unit.ts"
21+
}
22+
},
1723
"lint": {
1824
"executor": "@nx/linter:eslint",
1925
"outputs": ["{options.outputFile}"],
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import type { SyncExpectationResult } from '@vitest/expect';
2+
import { expect } from 'vitest';
3+
import { osAgnosticPath } from '@code-pushup/test-utils';
4+
5+
export type CustomPathMatchers = {
6+
toMatchPath: (path: string) => void;
7+
toStartWithPath: (path: string) => void;
8+
toContainPath: (path: string) => void;
9+
toEndWithPath: (path: string) => void;
10+
};
11+
12+
export type CustomAsymmetricPathMatchers = {
13+
/* eslint-disable @typescript-eslint/no-explicit-any */
14+
pathToMatch: (path: string) => any;
15+
pathToStartWith: (path: string) => any;
16+
pathToContain: (path: string) => any;
17+
pathToEndWith: (path: string) => any;
18+
/* eslint-enable @typescript-eslint/no-explicit-any */
19+
};
20+
21+
expect.extend({
22+
toMatchPath: assertPathMatch,
23+
pathToMatch: assertPathMatch,
24+
toStartWithPath: assertPathStartWith,
25+
pathToStartWith: assertPathStartWith,
26+
toContainPath: assertPathContain,
27+
pathToContain: assertPathContain,
28+
toEndWithPath: assertPathEndWith,
29+
pathToEndWith: assertPathEndWith,
30+
});
31+
32+
function assertPathMatch(
33+
actual: string,
34+
expected: string,
35+
): SyncExpectationResult {
36+
const normalizedReceived = osAgnosticPath(actual);
37+
const normalizedExpected = osAgnosticPath(expected);
38+
39+
const pass = normalizedReceived === normalizedExpected;
40+
return pass
41+
? {
42+
message: () => `expected ${actual} not to match path ${expected}`,
43+
pass: true,
44+
actual,
45+
expected,
46+
}
47+
: {
48+
message: () => `expected ${actual} to match path ${expected}`,
49+
pass: false,
50+
actual,
51+
expected,
52+
};
53+
}
54+
55+
function assertPathStartWith(
56+
actual: string,
57+
expected: string,
58+
): SyncExpectationResult {
59+
const normalizedReceived = osAgnosticPath(actual);
60+
const normalizedExpected = osAgnosticPath(expected);
61+
62+
const pass = normalizedReceived.startsWith(normalizedExpected);
63+
return pass
64+
? {
65+
message: () => `expected ${actual} not to start with path ${expected}`,
66+
pass: true,
67+
actual,
68+
expected,
69+
}
70+
: {
71+
message: () => `expected ${actual} to start with path ${expected}`,
72+
pass: false,
73+
actual,
74+
expected,
75+
};
76+
}
77+
78+
function assertPathContain(
79+
actual: string,
80+
expected: string,
81+
): SyncExpectationResult {
82+
const normalizedReceived = osAgnosticPath(actual);
83+
const normalizedExpected = osAgnosticPath(expected);
84+
85+
const pass = normalizedReceived.includes(normalizedExpected);
86+
return pass
87+
? {
88+
message: () => `expected ${actual} not to contain path ${expected}`,
89+
pass: true,
90+
actual,
91+
expected,
92+
}
93+
: {
94+
message: () => `expected ${actual} to contain path ${expected}`,
95+
pass: false,
96+
actual,
97+
expected,
98+
};
99+
}
100+
101+
function assertPathEndWith(
102+
actual: string,
103+
expected: string,
104+
): SyncExpectationResult {
105+
const normalizedReceived = osAgnosticPath(actual);
106+
const normalizedExpected = osAgnosticPath(expected);
107+
108+
const pass = normalizedReceived.endsWith(normalizedExpected);
109+
return pass
110+
? {
111+
message: () => `expected ${actual} not to end with path ${expected}`,
112+
pass: true,
113+
actual,
114+
expected,
115+
}
116+
: {
117+
message: () => `expected ${actual} to end with path ${expected}`,
118+
pass: false,
119+
actual,
120+
expected,
121+
};
122+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { describe, expect, it, vi } from 'vitest';
2+
import * as testUtils from '@code-pushup/test-utils';
3+
4+
describe('path-matcher', () => {
5+
const osAgnosticPathSpy = vi.spyOn(testUtils, 'osAgnosticPath');
6+
7+
it('should provide "toMatchPath" as expect matcher', () => {
8+
const actual = String.raw`tmp\path\to\file.txt`;
9+
const expected = 'tmp/path/to/file.txt';
10+
11+
expect(actual).toMatchPath(expected);
12+
13+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
14+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
15+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
16+
});
17+
18+
it('should provide "pathToMatch" as expect matcher', () => {
19+
const actual = String.raw`tmp\path\to\file.txt`;
20+
const expected = 'tmp/path/to/file.txt';
21+
22+
expect({ path: actual }).toStrictEqual({
23+
path: expect.pathToMatch(expected),
24+
});
25+
26+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
27+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
28+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
29+
});
30+
31+
it('should provide "toStartWithPath" as expect matcher', () => {
32+
const actual = String.raw`tmp\path\to\file.txt`;
33+
const expected = 'tmp/path/to';
34+
35+
expect(actual).toStartWithPath(expected);
36+
37+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
38+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
39+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
40+
});
41+
42+
it('should provide "pathToStartWith" as expect matcher', () => {
43+
const actual = String.raw`tmp\path\to\file.txt`;
44+
const expected = 'tmp/path/to';
45+
46+
expect({ path: actual }).toStrictEqual({
47+
path: expect.pathToStartWith(expected),
48+
});
49+
50+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
51+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
52+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
53+
});
54+
55+
it('should provide "toContainPath" as expect matcher', () => {
56+
const actual = String.raw`tmp\path\to\file.txt`;
57+
const expected = 'path/to';
58+
59+
expect(actual).toContainPath(expected);
60+
61+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
62+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
63+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
64+
});
65+
66+
it('should provide "pathToContain" as expect matcher', () => {
67+
const actual = String.raw`tmp\path\to\file.txt`;
68+
const expected = 'path/to';
69+
70+
expect({ path: actual }).toStrictEqual({
71+
path: expect.pathToContain(expected),
72+
});
73+
74+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
75+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
76+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
77+
});
78+
79+
it('should provide "toEndWithPath" as expect matcher', () => {
80+
const actual = String.raw`tmp\path\to\file.txt`;
81+
const expected = 'path/to/file.txt';
82+
83+
expect(actual).toEndWithPath(expected);
84+
85+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
86+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
87+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
88+
});
89+
90+
it('should provide "pathToEndWith" as expect matcher', () => {
91+
const actual = String.raw`tmp\path\to\file.txt`;
92+
const expected = 'path/to/file.txt';
93+
94+
expect({ path: actual }).toStrictEqual({
95+
path: expect.pathToEndWith(expected),
96+
});
97+
98+
expect(osAgnosticPathSpy).toHaveBeenCalledTimes(2);
99+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(actual);
100+
expect(osAgnosticPathSpy).toHaveBeenCalledWith(expected);
101+
});
102+
});

testing/test-setup/src/vitest.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* eslint-disable @typescript-eslint/consistent-type-definitions */
2+
import type {
3+
CustomAsymmetricPathMatchers,
4+
CustomPathMatchers,
5+
} from './lib/extend/path.matcher.js';
6+
7+
declare module 'vitest' {
8+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
9+
interface Assertion extends CustomPathMatchers {}
10+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
11+
interface AsymmetricMatchersContaining extends CustomAsymmetricPathMatchers {}
12+
}
13+
/* eslint-enable @typescript-eslint/consistent-type-definitions */

0 commit comments

Comments
 (0)