Skip to content

Commit da9891e

Browse files
committed
test(test-setup): add custom path matcher to vitest, add tests
1 parent 7e6c29d commit da9891e

File tree

7 files changed

+329
-1
lines changed

7 files changed

+329
-1
lines changed

testing/test-setup/project.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
"esbuildConfig": "esbuild.config.js"
1616
}
1717
},
18+
"unit-test": {
19+
"executor": "@nx/vite:test",
20+
"options": {
21+
"configFile": "testing/test-setup/vite.config.unit.ts"
22+
}
23+
},
1824
"lint": {
1925
"executor": "@nx/linter:eslint",
2026
"outputs": ["{options.outputFile}"],
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// types/vitest.d.ts
2+
import 'vitest';
3+
4+
declare module 'vitest' {
5+
type Assertion<T = any> = {
6+
toMatchPath(path: string): void;
7+
toStartWithPath(path: string): void;
8+
toContainPath(path: string): void;
9+
toEndWithPath(path: string): void;
10+
}
11+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import type { SyncExpectationResult } from '@vitest/expect';
2+
import { expect } from 'vitest';
3+
import { osAgnosticPath } from '@code-pushup/test-utils';
4+
5+
expect.extend({
6+
toMatchPath(actual: string, expected: string): SyncExpectationResult {
7+
const normalizedReceived = osAgnosticPath(actual);
8+
const normalizedExpected = osAgnosticPath(expected);
9+
10+
const pass = normalizedReceived === normalizedExpected;
11+
return pass
12+
? {
13+
message: () => `expected ${actual} not to match path ${expected}`,
14+
pass: true,
15+
actual,
16+
expected,
17+
}
18+
: {
19+
message: () => `expected ${actual} to match path ${expected}`,
20+
pass: false,
21+
actual,
22+
expected,
23+
};
24+
},
25+
26+
pathToMatch(actual: string, expected: string): SyncExpectationResult {
27+
const normalizedReceived = osAgnosticPath(actual);
28+
const normalizedExpected = osAgnosticPath(expected);
29+
30+
const pass = normalizedReceived === normalizedExpected;
31+
return pass
32+
? {
33+
message: () => `expected ${actual} not to match path ${expected}`,
34+
pass: true,
35+
actual,
36+
expected,
37+
}
38+
: {
39+
message: () => `expected ${actual} to match path ${expected}`,
40+
pass: false,
41+
actual,
42+
expected,
43+
};
44+
},
45+
46+
toStartWithPath(actual: string, expected: string): SyncExpectationResult {
47+
const normalizedReceived = osAgnosticPath(actual);
48+
const normalizedExpected = osAgnosticPath(expected);
49+
50+
const pass = normalizedReceived.startsWith(normalizedExpected);
51+
return pass
52+
? {
53+
message: () =>
54+
`expected ${actual} not to starts with path ${expected}`,
55+
pass: true,
56+
actual,
57+
expected,
58+
}
59+
: {
60+
message: () => `expected ${actual} to starts with path ${expected}`,
61+
pass: false,
62+
actual,
63+
expected,
64+
};
65+
},
66+
67+
pathToStartWith(actual: string, expected: string): SyncExpectationResult {
68+
const normalizedReceived = osAgnosticPath(actual);
69+
const normalizedExpected = osAgnosticPath(expected);
70+
71+
const pass = normalizedReceived.startsWith(normalizedExpected);
72+
return pass
73+
? {
74+
message: () =>
75+
`expected ${actual} not to starts with path ${expected}`,
76+
pass: true,
77+
actual,
78+
expected,
79+
}
80+
: {
81+
message: () => `expected ${actual} to starts with path ${expected}`,
82+
pass: false,
83+
actual,
84+
expected,
85+
};
86+
},
87+
88+
toContainPath(actual: string, expected: string): SyncExpectationResult {
89+
const normalizedReceived = osAgnosticPath(actual);
90+
const normalizedExpected = osAgnosticPath(expected);
91+
92+
const pass = normalizedReceived.includes(normalizedExpected);
93+
return pass
94+
? {
95+
message: () => `expected ${actual} not to contain path ${expected}`,
96+
pass: true,
97+
actual,
98+
expected,
99+
}
100+
: {
101+
message: () => `expected ${actual} to contain path ${expected}`,
102+
pass: false,
103+
actual,
104+
expected,
105+
};
106+
},
107+
108+
pathToContain(actual: string, expected: string): SyncExpectationResult {
109+
const normalizedReceived = osAgnosticPath(actual);
110+
const normalizedExpected = osAgnosticPath(expected);
111+
112+
const pass = normalizedReceived.includes(normalizedExpected);
113+
return pass
114+
? {
115+
message: () => `expected ${actual} not to contain path ${expected}`,
116+
pass: true,
117+
actual,
118+
expected,
119+
}
120+
: {
121+
message: () => `expected ${actual} to contain path ${expected}`,
122+
pass: false,
123+
actual,
124+
expected,
125+
};
126+
},
127+
toEndWithPath(actual: string, expected: string): SyncExpectationResult {
128+
const normalizedReceived = osAgnosticPath(actual);
129+
const normalizedExpected = osAgnosticPath(expected);
130+
131+
const pass = normalizedReceived.endsWith(normalizedExpected);
132+
return pass
133+
? {
134+
message: () => `expected ${actual} not to ends with path ${expected}`,
135+
pass: true,
136+
actual,
137+
expected,
138+
}
139+
: {
140+
message: () => `expected ${actual} to ends with path ${expected}`,
141+
pass: false,
142+
actual,
143+
expected,
144+
};
145+
},
146+
147+
pathToEndWith(actual: string, expected: string): SyncExpectationResult {
148+
const normalizedReceived = osAgnosticPath(actual);
149+
const normalizedExpected = osAgnosticPath(expected);
150+
151+
const pass = normalizedReceived.endsWith(normalizedExpected);
152+
return pass
153+
? {
154+
message: () => `expected ${actual} not to ends with path ${expected}`,
155+
pass: true,
156+
actual,
157+
expected,
158+
}
159+
: {
160+
message: () => `expected ${actual} to ends with path ${expected}`,
161+
pass: false,
162+
actual,
163+
expected,
164+
};
165+
},
166+
});
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 = '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 = '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 = '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 = '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 = '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 = '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 = '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 = '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+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "../../dist/out-tsc",
5+
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"]
6+
},
7+
"include": [
8+
"vite.config.unit.ts",
9+
"src/**/*.unit.test.ts",
10+
"src/**/*.d.ts",
11+
"src/**/*.integration.test.ts"
12+
]
13+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// <reference types="vitest" />
2+
import { defineConfig } from 'vite';
3+
import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases';
4+
5+
export default defineConfig({
6+
cacheDir: '../node_modules/.vite/test-setup',
7+
test: {
8+
reporters: ['basic'],
9+
globals: true,
10+
cache: {
11+
dir: '../node_modules/.vitest',
12+
},
13+
alias: tsconfigPathAliases(),
14+
pool: 'threads',
15+
poolOptions: { threads: { singleThread: true } },
16+
coverage: {
17+
reporter: ['text', 'lcov'],
18+
reportsDirectory: '../../coverage/test-setup/unit-tests',
19+
exclude: ['**/*.mock.{mjs,ts}', '**/*.config.{js,mjs,ts}'],
20+
},
21+
environment: 'node',
22+
include: ['src/**/*.unit.test.ts'],
23+
setupFiles: [
24+
'../test-setup/src/lib/reset.mocks.ts',
25+
'../test-setup/src/lib/extend/path.matcher.ts',
26+
],
27+
},
28+
});

testing/test-utils/tsconfig.lib.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"declaration": true,
66
"types": ["node"]
77
},
8-
"include": ["src/**/*.ts"],
8+
"include": [
9+
"src/**/*.ts"
10+
],
911
"exclude": [
1012
"vite.config.unit.ts",
1113
"src/**/*.unit.test.ts",

0 commit comments

Comments
 (0)