@application-kit/testing 0.10.0 → 0.10.2

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,21 @@
1
1
  # @application-kit/testing
2
2
 
3
+ ## 0.10.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [c9f24d0]
8
+ - @application-kit/bootstrap@0.3.0
9
+
10
+ ## 0.10.1
11
+
12
+ ### Patch Changes
13
+
14
+ - 0b5ce72: `defineStrykerLayers` убирает из incremental-отчёта `Survived` статических мутантов (без `coveredBy`): Stryker
15
+ переиспользует такой статус бессрочно, и починка спека не поднимает score группы. Мутант планируется заново и под
16
+ `ignoreStatic` становится `Ignored` без прогона тестов.
17
+ - 81eb99a: Фабрики конфигов vitest пускают `@application-kit/audit-log` через Vite вместе с `@application-kit/graphql`: нативный `import` давал журналу второй экземпляр `@application-kit/graphql`, и схема GraphQL падала на дубле `CursorOutputType`. Продукту больше не нужно перечислять журнал в `inlineDependencies`.
18
+
3
19
  ## 0.10.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -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 берёт
@@ -22,6 +22,9 @@ const MATRIX_PATTERN = (variable) => {
22
22
  const sorted = (values) => [...values].toSorted((left, right) => left.localeCompare(right));
23
23
  const isUnderDirectory = (file, directory) => file.startsWith(`${directory}/`);
24
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);
25
28
  const rootsOf = (options) => [
26
29
  ...options.scope.directories,
27
30
  ...options.scope.parents.flatMap((parent) => (0, node_fs_1.readdirSync)(node_path_1.default.join(options.root, parent), { withFileTypes: true })
@@ -62,18 +65,20 @@ const pruneIncrementalReport = (incrementalFile, isInScope, configName) => {
62
65
  const report = JSON.parse((0, node_fs_1.readFileSync)(incrementalFile, 'utf8'));
63
66
  const files = Object.entries(report.files ?? {});
64
67
  const own = files.filter(([file]) => isInScope(file));
65
- const uncovered = own.flatMap(([, data]) => data.mutants).filter((mutant) => isUncovered(mutant));
66
- 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) {
67
72
  return;
68
73
  }
69
74
  report.files = Object.fromEntries(own.map(([file, data]) => [
70
75
  file,
71
- { ...data, mutants: data.mutants.filter((mutant) => !isUncovered(mutant)) },
76
+ { ...data, mutants: data.mutants.filter((mutant) => !isStale(mutant)) },
72
77
  ]));
73
78
  (0, node_fs_1.writeFileSync)(`${incrementalFile}.tmp`, JSON.stringify(report));
74
79
  (0, node_fs_1.renameSync)(`${incrementalFile}.tmp`, incrementalFile);
75
80
  console.error(`${configName}: из ${incrementalFile} убрано файлов вне области группы: ${files.length - own.length}, `
76
- + `мутантов NoCoverage: ${uncovered.length}`);
81
+ + `мутантов NoCoverage: ${uncovered.length}, Survived без покрытия: ${staticSurvived.length}`);
77
82
  };
78
83
  const defineStrykerLayers = (options) => {
79
84
  const variable = options.layerVariable ?? DEFAULT_LAYER_VARIABLE;
@@ -11,7 +11,7 @@ const vite_1 = require("vite");
11
11
  const node_1 = require("vitest/node");
12
12
  const code_without_logic_js_1 = require("../stryker/code-without-logic.js");
13
13
  const project_shard_sequencer_js_1 = require("./project-shard-sequencer.js");
14
- const PACKAGES_THROUGH_VITE = ['@application-kit/graphql'];
14
+ const PACKAGES_THROUGH_VITE = ['@application-kit/graphql', '@application-kit/audit-log'];
15
15
  const TEST_TIMEOUT = 20_000;
16
16
  const MODULE_CACHE_PATH = '.vitest-module-cache';
17
17
  const IS_VITEST_5 = Number(node_1.version.split('.', 1)[0]) >= 5;
@@ -16,6 +16,9 @@ const MATRIX_PATTERN = (variable) => {
16
16
  const sorted = (values) => [...values].toSorted((left, right) => left.localeCompare(right));
17
17
  const isUnderDirectory = (file, directory) => file.startsWith(`${directory}/`);
18
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);
19
22
  const rootsOf = (options) => [
20
23
  ...options.scope.directories,
21
24
  ...options.scope.parents.flatMap((parent) => readdirSync(path.join(options.root, parent), { withFileTypes: true })
@@ -56,18 +59,20 @@ const pruneIncrementalReport = (incrementalFile, isInScope, configName) => {
56
59
  const report = JSON.parse(readFileSync(incrementalFile, 'utf8'));
57
60
  const files = Object.entries(report.files ?? {});
58
61
  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) {
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) {
61
66
  return;
62
67
  }
63
68
  report.files = Object.fromEntries(own.map(([file, data]) => [
64
69
  file,
65
- { ...data, mutants: data.mutants.filter((mutant) => !isUncovered(mutant)) },
70
+ { ...data, mutants: data.mutants.filter((mutant) => !isStale(mutant)) },
66
71
  ]));
67
72
  writeFileSync(`${incrementalFile}.tmp`, JSON.stringify(report));
68
73
  renameSync(`${incrementalFile}.tmp`, incrementalFile);
69
74
  console.error(`${configName}: из ${incrementalFile} убрано файлов вне области группы: ${files.length - own.length}, `
70
- + `мутантов NoCoverage: ${uncovered.length}`);
75
+ + `мутантов NoCoverage: ${uncovered.length}, Survived без покрытия: ${staticSurvived.length}`);
71
76
  };
72
77
  export const defineStrykerLayers = (options) => {
73
78
  const variable = options.layerVariable ?? DEFAULT_LAYER_VARIABLE;
@@ -5,7 +5,7 @@ import { mergeConfig } from 'vite';
5
5
  import { version } from 'vitest/node';
6
6
  import { CODE_WITHOUT_LOGIC } from '../stryker/code-without-logic.js';
7
7
  import { parseShard, ProjectShardSequencer } from './project-shard-sequencer.js';
8
- const PACKAGES_THROUGH_VITE = ['@application-kit/graphql'];
8
+ const PACKAGES_THROUGH_VITE = ['@application-kit/graphql', '@application-kit/audit-log'];
9
9
  const TEST_TIMEOUT = 20_000;
10
10
  const MODULE_CACHE_PATH = '.vitest-module-cache';
11
11
  const IS_VITEST_5 = Number(version.split('.', 1)[0]) >= 5;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@application-kit/testing",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
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.4"
84
+ "@application-kit/bootstrap": "^0.3.0"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@nestjs/common": "^11.2.7",