@application-kit/testing 0.9.0 → 0.10.1

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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # @application-kit/testing
2
2
 
3
+ ## 0.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0b5ce72: `defineStrykerLayers` убирает из incremental-отчёта `Survived` статических мутантов (без `coveredBy`): Stryker
8
+ переиспользует такой статус бессрочно, и починка спека не поднимает score группы. Мутант планируется заново и под
9
+ `ignoreStatic` становится `Ignored` без прогона тестов.
10
+ - 81eb99a: Фабрики конфигов vitest пускают `@application-kit/audit-log` через Vite вместе с `@application-kit/graphql`: нативный `import` давал журналу второй экземпляр `@application-kit/graphql`, и схема GraphQL падала на дубле `CursorOutputType`. Продукту больше не нужно перечислять журнал в `inlineDependencies`.
11
+
12
+ ## 0.10.0
13
+
14
+ ### Minor Changes
15
+
16
+ - 9cf88e4: Универсальные настройки конфигов приложения стали умолчаниями пресетов: конфиг продукта называет только продукт.
17
+
18
+ `testing`: `defineStrykerConfig` сам исключает спеки, `tests/` и `.vue` и служебные каталоги, `vitestConfigFile` необязателен. У `defineStrykerLayers` необязательны `skip.configFiles` и `skip.sourceRoot`. Unit-профиль vitest сам исключает из покрытия `CODE_WITHOUT_LOGIC`, `*.exception.ts`, `*.html` и `src/*.ts`.
19
+
20
+ `lint-config`: пресет игнорирует служебные каталоги и выключает `unicorn/prefer-temporal`. Новый вход `lint-config/translated-files` — `defineTranslatedFilesConfig` с запретом литералов в переведённых экранах; плагин `@intlify/eslint-plugin-vue-i18n` — optional peer.
21
+
22
+ Что сделать потребителю: убрать из своих конфигов перечисленное, оно теперь дублирует умолчания. Список в `coverage.exclude`, `mutate.exclude` или `ignores`, отличный от умолчаний, продолжает работать как добавка, но снять умолчание больше нельзя.
23
+
3
24
  ## 0.9.0
4
25
 
5
26
  ### 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: { exclude: ['**/*.module.ts'], include: ['src'], thresholds: { lines: 95 } },
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'],
@@ -89,7 +89,9 @@ export default defineApplicationEndToEndConfig({
89
89
  кеш трансформов `.vitest-module-cache` (путь — контракт кеша джоб `ts:test:*` шаблона CI; ключ — `fsModuleCache`
90
90
  верхнего уровня на vitest 5 и `experimental.fsModuleCache` на vitest 4), покрытие v8 с отчётом
91
91
  `text` и `skipFull`; `@application-kit/graphql` идёт через Vite, а не нативно через Node — иначе ошибка из пакета и код
92
- приложения видят разные копии `graphql`, и `instanceof GraphQLError` ложен;
92
+ приложения видят разные копии `graphql`, и `instanceof GraphQLError` ложен; тем же путём идёт пакет, импортирующий
93
+ `@application-kit/graphql` (`@application-kit/audit-log`), — нативный `import` дал бы ему второй экземпляр пакета, и
94
+ схема GraphQL падает на дубле `CursorOutputType`;
93
95
  - unit — проекты `server` (`node`, спеки `specs` без `excludeSpecs` и `clientSpecs`) и `client` (`jsdom`, `clientSpecs`),
94
96
  ячейки шарда CI и `ProjectShardSequencer` (ниже);
95
97
  - e2e — окружение `node` и алиас `graphql` на CJS-вход `node_modules/graphql/index.js` под `root`: Vite для SSR берёт
@@ -131,23 +133,21 @@ web-карту того же файла, и statements/functions задваив
131
133
  Вход не тянет `vitest`: конфиг Stryker — обычный объект. `stryker.config.mjs` приложения собирается из трёх частей.
132
134
 
133
135
  `CODE_WITHOUT_LOGIC` — глобы файлов без логики (команды, DTO, модули, мапперы, манифесты, сущности и миграции TypeORM,
134
- навигация, виджет-плагины). Список один на оба инструмента: `defineStrykerConfig` добавляет к нему `!` для `mutate`, а
135
- приложение кладёт его в `coverage.exclude` vitest. Расхождение допустимо только в явных добавках приложения:
136
- `*.spec.ts` и `tests/**` для мутаций, `*.html` для покрытия.
136
+ навигация, виджет-плагины). Список один на оба инструмента, и пресеты подключают его сами: `defineStrykerConfig` добавляет
137
+ к нему `!` для `mutate`, unit-профиль vitest кладёт его в `coverage.exclude`. Сверх него `defineStrykerConfig` исключает
138
+ `*.spec.ts`, `*.vue` и `tests/**`, а unit-профиль — `*.exception.ts`, `*.html` и `src/*.ts`.
137
139
 
138
140
  ```js
139
- import { CODE_WITHOUT_LOGIC, defineStrykerConfig } from '@application-kit/testing/stryker'
141
+ import { defineStrykerConfig } from '@application-kit/testing/stryker'
140
142
 
141
143
  // stryker.conf.mjs — база
142
144
  export default defineStrykerConfig({
143
- ignorePatterns: ['docs', 'tasks'],
144
- mutate: { exclude: ['src/**/*.spec.ts', 'src/**/*.vue', 'src/**/tests/**'], include: ['src/modules/**/*.ts', 'src/libs/**/*.ts'] },
145
+ mutate: { exclude: ['src/libs/testing-module/**'], include: ['src/modules/**/*.ts', 'src/libs/**/*.ts'] },
145
146
  thresholds: { break: 94, high: 100, low: 95 },
146
- vitestConfigFile: 'vitest.config.mts',
147
147
  })
148
148
 
149
149
  // vitest.config.mts
150
- coverage: { exclude: [...CODE_WITHOUT_LOGIC, '**/*.html'], include: ['src'], thresholds: { lines: 95 } }
150
+ coverage: { include: ['src'], thresholds: { lines: 95 } }
151
151
  ```
152
152
 
153
153
  `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 = ['coverage', 'dist', 'node_modules', 'reports'];
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) => {
@@ -16,6 +22,9 @@ const MATRIX_PATTERN = (variable) => {
16
22
  const sorted = (values) => [...values].toSorted((left, right) => left.localeCompare(right));
17
23
  const isUnderDirectory = (file, directory) => file.startsWith(`${directory}/`);
18
24
  const isUncovered = (mutant) => mutant.status === 'NoCoverage';
25
+ const isStaticSurvived = (mutant) => mutant.status === 'Survived'
26
+ && (mutant.coveredBy ?? []).length === 0;
27
+ const isStale = (mutant) => isUncovered(mutant) || isStaticSurvived(mutant);
19
28
  const rootsOf = (options) => [
20
29
  ...options.scope.directories,
21
30
  ...options.scope.parents.flatMap((parent) => (0, node_fs_1.readdirSync)(node_path_1.default.join(options.root, parent), { withFileTypes: true })
@@ -56,18 +65,20 @@ const pruneIncrementalReport = (incrementalFile, isInScope, configName) => {
56
65
  const report = JSON.parse((0, node_fs_1.readFileSync)(incrementalFile, 'utf8'));
57
66
  const files = Object.entries(report.files ?? {});
58
67
  const own = files.filter(([file]) => isInScope(file));
59
- const uncovered = own.flatMap(([, data]) => data.mutants).filter((mutant) => isUncovered(mutant));
60
- if (own.length === files.length && uncovered.length === 0) {
68
+ const mutants = own.flatMap(([, data]) => data.mutants);
69
+ const uncovered = mutants.filter((mutant) => isUncovered(mutant));
70
+ const staticSurvived = mutants.filter((mutant) => isStaticSurvived(mutant));
71
+ if (own.length === files.length && uncovered.length === 0 && staticSurvived.length === 0) {
61
72
  return;
62
73
  }
63
74
  report.files = Object.fromEntries(own.map(([file, data]) => [
64
75
  file,
65
- { ...data, mutants: data.mutants.filter((mutant) => !isUncovered(mutant)) },
76
+ { ...data, mutants: data.mutants.filter((mutant) => !isStale(mutant)) },
66
77
  ]));
67
78
  (0, node_fs_1.writeFileSync)(`${incrementalFile}.tmp`, JSON.stringify(report));
68
79
  (0, node_fs_1.renameSync)(`${incrementalFile}.tmp`, incrementalFile);
69
80
  console.error(`${configName}: из ${incrementalFile} убрано файлов вне области группы: ${files.length - own.length}, `
70
- + `мутантов NoCoverage: ${uncovered.length}`);
81
+ + `мутантов NoCoverage: ${uncovered.length}, Survived без покрытия: ${staticSurvived.length}`);
71
82
  };
72
83
  const defineStrykerLayers = (options) => {
73
84
  const variable = options.layerVariable ?? DEFAULT_LAYER_VARIABLE;
@@ -113,7 +124,7 @@ const defineStrykerLayers = (options) => {
113
124
  names,
114
125
  paths: pathsOf,
115
126
  roots,
116
- skip: options.skip,
127
+ skip: resolveSkip(options.skip),
117
128
  };
118
129
  };
119
130
  exports.defineStrykerLayers = defineStrykerLayers;
@@ -10,7 +10,7 @@ export interface StrykerConfigOptionsInterface {
10
10
  mutate: StrykerMutateScopeInterface;
11
11
  tempDirName?: string;
12
12
  thresholds: StrykerThresholdsInterface;
13
- vitestConfigFile: string;
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: StrykerLayerSkipOptionsInterface;
33
+ skip: StrykerLayerSkipScopeInterface;
31
34
  }
@@ -9,8 +9,9 @@ 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
- const PACKAGES_THROUGH_VITE = ['@application-kit/graphql'];
14
+ const PACKAGES_THROUGH_VITE = ['@application-kit/graphql', '@application-kit/audit-log'];
14
15
  const TEST_TIMEOUT = 20_000;
15
16
  const MODULE_CACHE_PATH = '.vitest-module-cache';
16
17
  const IS_VITEST_5 = Number(node_1.version.split('.', 1)[0]) >= 5;
@@ -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: [...(cell === 'server' ? options.clientSources : []), ...(options.coverage.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 = ['coverage', 'dist', 'node_modules', 'reports'];
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) => {
@@ -10,6 +16,9 @@ const MATRIX_PATTERN = (variable) => {
10
16
  const sorted = (values) => [...values].toSorted((left, right) => left.localeCompare(right));
11
17
  const isUnderDirectory = (file, directory) => file.startsWith(`${directory}/`);
12
18
  const isUncovered = (mutant) => mutant.status === 'NoCoverage';
19
+ const isStaticSurvived = (mutant) => mutant.status === 'Survived'
20
+ && (mutant.coveredBy ?? []).length === 0;
21
+ const isStale = (mutant) => isUncovered(mutant) || isStaticSurvived(mutant);
13
22
  const rootsOf = (options) => [
14
23
  ...options.scope.directories,
15
24
  ...options.scope.parents.flatMap((parent) => readdirSync(path.join(options.root, parent), { withFileTypes: true })
@@ -50,18 +59,20 @@ const pruneIncrementalReport = (incrementalFile, isInScope, configName) => {
50
59
  const report = JSON.parse(readFileSync(incrementalFile, 'utf8'));
51
60
  const files = Object.entries(report.files ?? {});
52
61
  const own = files.filter(([file]) => isInScope(file));
53
- const uncovered = own.flatMap(([, data]) => data.mutants).filter((mutant) => isUncovered(mutant));
54
- if (own.length === files.length && uncovered.length === 0) {
62
+ const mutants = own.flatMap(([, data]) => data.mutants);
63
+ const uncovered = mutants.filter((mutant) => isUncovered(mutant));
64
+ const staticSurvived = mutants.filter((mutant) => isStaticSurvived(mutant));
65
+ if (own.length === files.length && uncovered.length === 0 && staticSurvived.length === 0) {
55
66
  return;
56
67
  }
57
68
  report.files = Object.fromEntries(own.map(([file, data]) => [
58
69
  file,
59
- { ...data, mutants: data.mutants.filter((mutant) => !isUncovered(mutant)) },
70
+ { ...data, mutants: data.mutants.filter((mutant) => !isStale(mutant)) },
60
71
  ]));
61
72
  writeFileSync(`${incrementalFile}.tmp`, JSON.stringify(report));
62
73
  renameSync(`${incrementalFile}.tmp`, incrementalFile);
63
74
  console.error(`${configName}: из ${incrementalFile} убрано файлов вне области группы: ${files.length - own.length}, `
64
- + `мутантов NoCoverage: ${uncovered.length}`);
75
+ + `мутантов NoCoverage: ${uncovered.length}, Survived без покрытия: ${staticSurvived.length}`);
65
76
  };
66
77
  export const defineStrykerLayers = (options) => {
67
78
  const variable = options.layerVariable ?? DEFAULT_LAYER_VARIABLE;
@@ -107,6 +118,6 @@ export const defineStrykerLayers = (options) => {
107
118
  names,
108
119
  paths: pathsOf,
109
120
  roots,
110
- skip: options.skip,
121
+ skip: resolveSkip(options.skip),
111
122
  };
112
123
  };
@@ -10,7 +10,7 @@ export interface StrykerConfigOptionsInterface {
10
10
  mutate: StrykerMutateScopeInterface;
11
11
  tempDirName?: string;
12
12
  thresholds: StrykerThresholdsInterface;
13
- vitestConfigFile: string;
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: StrykerLayerSkipOptionsInterface;
33
+ skip: StrykerLayerSkipScopeInterface;
31
34
  }
@@ -3,8 +3,9 @@ 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
- const PACKAGES_THROUGH_VITE = ['@application-kit/graphql'];
8
+ const PACKAGES_THROUGH_VITE = ['@application-kit/graphql', '@application-kit/audit-log'];
8
9
  const TEST_TIMEOUT = 20_000;
9
10
  const MODULE_CACHE_PATH = '.vitest-module-cache';
10
11
  const IS_VITEST_5 = Number(version.split('.', 1)[0]) >= 5;
@@ -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: [...(cell === 'server' ? options.clientSources : []), ...(options.coverage.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.9.0",
3
+ "version": "0.10.1",
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.3"
84
+ "@application-kit/bootstrap": "^0.2.4"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@nestjs/common": "^11.2.7",