@application-kit/testing 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +7 -9
- package/dist/cjs/stryker/define-stryker-config.js +16 -3
- package/dist/cjs/stryker/define-stryker-layers.js +7 -1
- package/dist/cjs/stryker/stryker-config.interface.d.ts +1 -1
- package/dist/cjs/stryker/stryker-layers.interface.d.ts +4 -1
- package/dist/cjs/vitest/application-vitest-config.js +7 -1
- package/dist/esm/stryker/define-stryker-config.js +16 -3
- package/dist/esm/stryker/define-stryker-layers.js +7 -1
- package/dist/esm/stryker/stryker-config.interface.d.ts +1 -1
- package/dist/esm/stryker/stryker-layers.interface.d.ts +4 -1
- package/dist/esm/vitest/application-vitest-config.js +7 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @application-kit/testing
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9cf88e4: Универсальные настройки конфигов приложения стали умолчаниями пресетов: конфиг продукта называет только продукт.
|
|
8
|
+
|
|
9
|
+
`testing`: `defineStrykerConfig` сам исключает спеки, `tests/` и `.vue` и служебные каталоги, `vitestConfigFile` необязателен. У `defineStrykerLayers` необязательны `skip.configFiles` и `skip.sourceRoot`. Unit-профиль vitest сам исключает из покрытия `CODE_WITHOUT_LOGIC`, `*.exception.ts`, `*.html` и `src/*.ts`.
|
|
10
|
+
|
|
11
|
+
`lint-config`: пресет игнорирует служебные каталоги и выключает `unicorn/prefer-temporal`. Новый вход `lint-config/translated-files` — `defineTranslatedFilesConfig` с запретом литералов в переведённых экранах; плагин `@intlify/eslint-plugin-vue-i18n` — optional peer.
|
|
12
|
+
|
|
13
|
+
Что сделать потребителю: убрать из своих конфигов перечисленное, оно теперь дублирует умолчания. Список в `coverage.exclude`, `mutate.exclude` или `ignores`, отличный от умолчаний, продолжает работать как добавка, но снять умолчание больше нельзя.
|
|
14
|
+
|
|
3
15
|
## 0.9.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ const E2E_SPECS = ['src/modules/*/tests/*.spec.ts']
|
|
|
62
62
|
export default defineApplicationUnitConfig({
|
|
63
63
|
clientSources: ['src/modules/*/user-interface/client/**'],
|
|
64
64
|
clientSpecs: ['src/modules/*/user-interface/client/**/*.spec.ts'],
|
|
65
|
-
coverage: {
|
|
65
|
+
coverage: { include: ['src'], thresholds: { lines: 95 } },
|
|
66
66
|
excludeSpecs: E2E_SPECS,
|
|
67
67
|
root: import.meta.dirname,
|
|
68
68
|
serverSetupFiles: ['@application-kit/testing/vitest/fast-bcrypt'],
|
|
@@ -131,23 +131,21 @@ web-карту того же файла, и statements/functions задваив
|
|
|
131
131
|
Вход не тянет `vitest`: конфиг Stryker — обычный объект. `stryker.config.mjs` приложения собирается из трёх частей.
|
|
132
132
|
|
|
133
133
|
`CODE_WITHOUT_LOGIC` — глобы файлов без логики (команды, DTO, модули, мапперы, манифесты, сущности и миграции TypeORM,
|
|
134
|
-
навигация, виджет-плагины). Список один на оба
|
|
135
|
-
|
|
136
|
-
`*.spec.ts` и `tests
|
|
134
|
+
навигация, виджет-плагины). Список один на оба инструмента, и пресеты подключают его сами: `defineStrykerConfig` добавляет
|
|
135
|
+
к нему `!` для `mutate`, unit-профиль vitest кладёт его в `coverage.exclude`. Сверх него `defineStrykerConfig` исключает
|
|
136
|
+
`*.spec.ts`, `*.vue` и `tests/**`, а unit-профиль — `*.exception.ts`, `*.html` и `src/*.ts`.
|
|
137
137
|
|
|
138
138
|
```js
|
|
139
|
-
import {
|
|
139
|
+
import { defineStrykerConfig } from '@application-kit/testing/stryker'
|
|
140
140
|
|
|
141
141
|
// stryker.conf.mjs — база
|
|
142
142
|
export default defineStrykerConfig({
|
|
143
|
-
|
|
144
|
-
mutate: { exclude: ['src/**/*.spec.ts', 'src/**/*.vue', 'src/**/tests/**'], include: ['src/modules/**/*.ts', 'src/libs/**/*.ts'] },
|
|
143
|
+
mutate: { exclude: ['src/libs/testing-module/**'], include: ['src/modules/**/*.ts', 'src/libs/**/*.ts'] },
|
|
145
144
|
thresholds: { break: 94, high: 100, low: 95 },
|
|
146
|
-
vitestConfigFile: 'vitest.config.mts',
|
|
147
145
|
})
|
|
148
146
|
|
|
149
147
|
// vitest.config.mts
|
|
150
|
-
coverage: {
|
|
148
|
+
coverage: { include: ['src'], thresholds: { lines: 95 } }
|
|
151
149
|
```
|
|
152
150
|
|
|
153
151
|
`defineStrykerLayers` режет прогон на группы каталогов: ячейка CI мутирует одну группу со своим порогом `break` (общий
|
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.defineStrykerConfig = void 0;
|
|
4
4
|
const code_without_logic_js_1 = require("./code-without-logic.js");
|
|
5
|
-
const DEFAULT_IGNORE_PATTERNS = [
|
|
5
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
6
|
+
'.claude',
|
|
7
|
+
'.cursor',
|
|
8
|
+
'.yarn',
|
|
9
|
+
'coverage',
|
|
10
|
+
'dist',
|
|
11
|
+
'docs',
|
|
12
|
+
'node_modules',
|
|
13
|
+
'reports',
|
|
14
|
+
'stryker.*.conf.*',
|
|
15
|
+
'tasks',
|
|
16
|
+
'var',
|
|
17
|
+
];
|
|
18
|
+
const NOT_MUTATED = ['src/**/*.spec.ts', 'src/**/*.vue', 'src/**/tests/**'];
|
|
6
19
|
const compare = (left, right) => left.localeCompare(right);
|
|
7
20
|
const defineStrykerConfig = (options) => ({
|
|
8
21
|
clearTextReporter: { reportTests: false },
|
|
@@ -14,11 +27,11 @@ const defineStrykerConfig = (options) => ({
|
|
|
14
27
|
logLevel: 'warn',
|
|
15
28
|
mutate: [
|
|
16
29
|
...options.mutate.include,
|
|
17
|
-
...[...code_without_logic_js_1.CODE_WITHOUT_LOGIC, ...(options.mutate.exclude ?? [])].map((pattern) => `!${pattern}`),
|
|
30
|
+
...[...code_without_logic_js_1.CODE_WITHOUT_LOGIC, ...NOT_MUTATED, ...(options.mutate.exclude ?? [])].map((pattern) => `!${pattern}`),
|
|
18
31
|
],
|
|
19
32
|
tempDirName: options.tempDirName ?? '/tmp/.stryker-tmp',
|
|
20
33
|
testRunner: 'vitest',
|
|
21
34
|
thresholds: options.thresholds,
|
|
22
|
-
vitest: { configFile: options.vitestConfigFile, dir: './' },
|
|
35
|
+
vitest: { configFile: options.vitestConfigFile ?? 'vitest.config.mts', dir: './' },
|
|
23
36
|
});
|
|
24
37
|
exports.defineStrykerConfig = defineStrykerConfig;
|
|
@@ -7,6 +7,12 @@ exports.defineStrykerLayers = void 0;
|
|
|
7
7
|
const node_fs_1 = require("node:fs");
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const node_process_1 = __importDefault(require("node:process"));
|
|
10
|
+
const DEFAULT_RUN_CONFIG_FILES = /^(?:\.gitlab-ci\.yml|tsconfig[^/]*\.json|vite\.config\.mts|vitest[^/]*\.mts|stryker[^/]*\.conf\.[a-z]+)$/u;
|
|
11
|
+
const resolveSkip = (scope) => ({
|
|
12
|
+
configFiles: scope.configFiles ?? DEFAULT_RUN_CONFIG_FILES,
|
|
13
|
+
sharedDirectories: scope.sharedDirectories,
|
|
14
|
+
sourceRoot: scope.sourceRoot ?? 'src',
|
|
15
|
+
});
|
|
10
16
|
const DEFAULT_LAYER_VARIABLE = 'TYPESCRIPT_MUTATION_LAYER';
|
|
11
17
|
const TEMPLATE_LAYER_SENTINEL = 'all';
|
|
12
18
|
const MATRIX_PATTERN = (variable) => {
|
|
@@ -113,7 +119,7 @@ const defineStrykerLayers = (options) => {
|
|
|
113
119
|
names,
|
|
114
120
|
paths: pathsOf,
|
|
115
121
|
roots,
|
|
116
|
-
skip: options.skip,
|
|
122
|
+
skip: resolveSkip(options.skip),
|
|
117
123
|
};
|
|
118
124
|
};
|
|
119
125
|
exports.defineStrykerLayers = defineStrykerLayers;
|
|
@@ -10,7 +10,7 @@ export interface StrykerConfigOptionsInterface {
|
|
|
10
10
|
mutate: StrykerMutateScopeInterface;
|
|
11
11
|
tempDirName?: string;
|
|
12
12
|
thresholds: StrykerThresholdsInterface;
|
|
13
|
-
vitestConfigFile
|
|
13
|
+
vitestConfigFile?: string;
|
|
14
14
|
}
|
|
15
15
|
export interface StrykerMutateScopeInterface {
|
|
16
16
|
exclude?: readonly string[];
|
|
@@ -15,6 +15,9 @@ export interface StrykerLayerSkipOptionsInterface {
|
|
|
15
15
|
sharedDirectories: readonly string[];
|
|
16
16
|
sourceRoot: string;
|
|
17
17
|
}
|
|
18
|
+
export interface StrykerLayerSkipScopeInterface extends Partial<StrykerLayerSkipOptionsInterface> {
|
|
19
|
+
sharedDirectories: readonly string[];
|
|
20
|
+
}
|
|
18
21
|
export interface StrykerLayersOptionsInterface {
|
|
19
22
|
base: StrykerConfigInterface;
|
|
20
23
|
ciFile: string;
|
|
@@ -27,5 +30,5 @@ export interface StrykerLayersOptionsInterface {
|
|
|
27
30
|
directories: readonly string[];
|
|
28
31
|
parents: readonly string[];
|
|
29
32
|
};
|
|
30
|
-
skip:
|
|
33
|
+
skip: StrykerLayerSkipScopeInterface;
|
|
31
34
|
}
|
|
@@ -9,6 +9,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
9
9
|
const node_process_1 = __importDefault(require("node:process"));
|
|
10
10
|
const vite_1 = require("vite");
|
|
11
11
|
const node_1 = require("vitest/node");
|
|
12
|
+
const code_without_logic_js_1 = require("../stryker/code-without-logic.js");
|
|
12
13
|
const project_shard_sequencer_js_1 = require("./project-shard-sequencer.js");
|
|
13
14
|
const PACKAGES_THROUGH_VITE = ['@application-kit/graphql'];
|
|
14
15
|
const TEST_TIMEOUT = 20_000;
|
|
@@ -74,8 +75,13 @@ const graphqlEntryOf = (root) => {
|
|
|
74
75
|
throw error;
|
|
75
76
|
}
|
|
76
77
|
};
|
|
78
|
+
const UNIT_COVERAGE_EXCLUDE = [...code_without_logic_js_1.CODE_WITHOUT_LOGIC, '**/*.exception.ts', '**/*.html', 'src/*.ts'];
|
|
77
79
|
const unitCoverageScope = (cell, options) => ({
|
|
78
|
-
exclude: [
|
|
80
|
+
exclude: [
|
|
81
|
+
...(cell === 'server' ? options.clientSources : []),
|
|
82
|
+
...UNIT_COVERAGE_EXCLUDE,
|
|
83
|
+
...(options.coverage.exclude ?? []),
|
|
84
|
+
],
|
|
79
85
|
include: cell === 'client' ? options.clientSources : options.coverage.include,
|
|
80
86
|
thresholds: options.coverage.thresholds,
|
|
81
87
|
});
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { CODE_WITHOUT_LOGIC } from './code-without-logic.js';
|
|
2
|
-
const DEFAULT_IGNORE_PATTERNS = [
|
|
2
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
3
|
+
'.claude',
|
|
4
|
+
'.cursor',
|
|
5
|
+
'.yarn',
|
|
6
|
+
'coverage',
|
|
7
|
+
'dist',
|
|
8
|
+
'docs',
|
|
9
|
+
'node_modules',
|
|
10
|
+
'reports',
|
|
11
|
+
'stryker.*.conf.*',
|
|
12
|
+
'tasks',
|
|
13
|
+
'var',
|
|
14
|
+
];
|
|
15
|
+
const NOT_MUTATED = ['src/**/*.spec.ts', 'src/**/*.vue', 'src/**/tests/**'];
|
|
3
16
|
const compare = (left, right) => left.localeCompare(right);
|
|
4
17
|
export const defineStrykerConfig = (options) => ({
|
|
5
18
|
clearTextReporter: { reportTests: false },
|
|
@@ -11,10 +24,10 @@ export const defineStrykerConfig = (options) => ({
|
|
|
11
24
|
logLevel: 'warn',
|
|
12
25
|
mutate: [
|
|
13
26
|
...options.mutate.include,
|
|
14
|
-
...[...CODE_WITHOUT_LOGIC, ...(options.mutate.exclude ?? [])].map((pattern) => `!${pattern}`),
|
|
27
|
+
...[...CODE_WITHOUT_LOGIC, ...NOT_MUTATED, ...(options.mutate.exclude ?? [])].map((pattern) => `!${pattern}`),
|
|
15
28
|
],
|
|
16
29
|
tempDirName: options.tempDirName ?? '/tmp/.stryker-tmp',
|
|
17
30
|
testRunner: 'vitest',
|
|
18
31
|
thresholds: options.thresholds,
|
|
19
|
-
vitest: { configFile: options.vitestConfigFile, dir: './' },
|
|
32
|
+
vitest: { configFile: options.vitestConfigFile ?? 'vitest.config.mts', dir: './' },
|
|
20
33
|
});
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import process from 'node:process';
|
|
4
|
+
const DEFAULT_RUN_CONFIG_FILES = /^(?:\.gitlab-ci\.yml|tsconfig[^/]*\.json|vite\.config\.mts|vitest[^/]*\.mts|stryker[^/]*\.conf\.[a-z]+)$/u;
|
|
5
|
+
const resolveSkip = (scope) => ({
|
|
6
|
+
configFiles: scope.configFiles ?? DEFAULT_RUN_CONFIG_FILES,
|
|
7
|
+
sharedDirectories: scope.sharedDirectories,
|
|
8
|
+
sourceRoot: scope.sourceRoot ?? 'src',
|
|
9
|
+
});
|
|
4
10
|
const DEFAULT_LAYER_VARIABLE = 'TYPESCRIPT_MUTATION_LAYER';
|
|
5
11
|
const TEMPLATE_LAYER_SENTINEL = 'all';
|
|
6
12
|
const MATRIX_PATTERN = (variable) => {
|
|
@@ -107,6 +113,6 @@ export const defineStrykerLayers = (options) => {
|
|
|
107
113
|
names,
|
|
108
114
|
paths: pathsOf,
|
|
109
115
|
roots,
|
|
110
|
-
skip: options.skip,
|
|
116
|
+
skip: resolveSkip(options.skip),
|
|
111
117
|
};
|
|
112
118
|
};
|
|
@@ -10,7 +10,7 @@ export interface StrykerConfigOptionsInterface {
|
|
|
10
10
|
mutate: StrykerMutateScopeInterface;
|
|
11
11
|
tempDirName?: string;
|
|
12
12
|
thresholds: StrykerThresholdsInterface;
|
|
13
|
-
vitestConfigFile
|
|
13
|
+
vitestConfigFile?: string;
|
|
14
14
|
}
|
|
15
15
|
export interface StrykerMutateScopeInterface {
|
|
16
16
|
exclude?: readonly string[];
|
|
@@ -15,6 +15,9 @@ export interface StrykerLayerSkipOptionsInterface {
|
|
|
15
15
|
sharedDirectories: readonly string[];
|
|
16
16
|
sourceRoot: string;
|
|
17
17
|
}
|
|
18
|
+
export interface StrykerLayerSkipScopeInterface extends Partial<StrykerLayerSkipOptionsInterface> {
|
|
19
|
+
sharedDirectories: readonly string[];
|
|
20
|
+
}
|
|
18
21
|
export interface StrykerLayersOptionsInterface {
|
|
19
22
|
base: StrykerConfigInterface;
|
|
20
23
|
ciFile: string;
|
|
@@ -27,5 +30,5 @@ export interface StrykerLayersOptionsInterface {
|
|
|
27
30
|
directories: readonly string[];
|
|
28
31
|
parents: readonly string[];
|
|
29
32
|
};
|
|
30
|
-
skip:
|
|
33
|
+
skip: StrykerLayerSkipScopeInterface;
|
|
31
34
|
}
|
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import process from 'node:process';
|
|
4
4
|
import { mergeConfig } from 'vite';
|
|
5
5
|
import { version } from 'vitest/node';
|
|
6
|
+
import { CODE_WITHOUT_LOGIC } from '../stryker/code-without-logic.js';
|
|
6
7
|
import { parseShard, ProjectShardSequencer } from './project-shard-sequencer.js';
|
|
7
8
|
const PACKAGES_THROUGH_VITE = ['@application-kit/graphql'];
|
|
8
9
|
const TEST_TIMEOUT = 20_000;
|
|
@@ -68,8 +69,13 @@ const graphqlEntryOf = (root) => {
|
|
|
68
69
|
throw error;
|
|
69
70
|
}
|
|
70
71
|
};
|
|
72
|
+
const UNIT_COVERAGE_EXCLUDE = [...CODE_WITHOUT_LOGIC, '**/*.exception.ts', '**/*.html', 'src/*.ts'];
|
|
71
73
|
const unitCoverageScope = (cell, options) => ({
|
|
72
|
-
exclude: [
|
|
74
|
+
exclude: [
|
|
75
|
+
...(cell === 'server' ? options.clientSources : []),
|
|
76
|
+
...UNIT_COVERAGE_EXCLUDE,
|
|
77
|
+
...(options.coverage.exclude ?? []),
|
|
78
|
+
],
|
|
73
79
|
include: cell === 'client' ? options.clientSources : options.coverage.include,
|
|
74
80
|
thresholds: options.coverage.thresholds,
|
|
75
81
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@application-kit/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Тестовая инфраструктура NestJS-приложений: шины CQRS, логгер, фейковый microservice, сборка web-приложения, Postgres в testcontainers, запуск e2e-приложения, изоляция окружения прогона, дешёвый bcrypt для unit-прогона, раскладка ячеек CI по проектам vitest и фабрики конфигов vitest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cqrs",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"test:unit": "vitest run"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@application-kit/bootstrap": "^0.2.
|
|
84
|
+
"@application-kit/bootstrap": "^0.2.4"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@nestjs/common": "^11.2.7",
|