test-inventory 0.3.0 → 0.4.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/dist/types.d.ts CHANGED
@@ -31,7 +31,7 @@ export type StateSource = 'test' | 'suite' | 'file';
31
31
  * @inline
32
32
  */
33
33
  export type DiagnosticLevel = 'error' | 'warning';
34
- export type DiagnosticCode = 'unresolved-test-import' | 'parse-error' | 'read-error' | 'framework-mismatch' | 'unresolved-tag' | 'unresolved-annotation' | 'unresolved-cases' | 'test-in-loop' | 'dynamic-title' | 'duplicate-title' | 'duplicate-id' | 'internal-error' | 'invalid-chain' | 'skip-without-body' | 'test-without-body' | 'describe-not-called' | 'async-describe' | 'nested-test' | 'tag-without-at' | 'removed-api' | 'only-in-skipped-describe' | 'config-may-change-state' | 'symlink-ignored' | 'invalid-import' | 'globals-not-enabled' | 'unknown-framework-version' | 'unsupported-framework-version' | 'local-test-object' | 'state-in-helper' | 'unresolved-option' | 'dynamic-reason' | 'no-files-matched' | 'unsupported-file' | 'approximate-framework-version' | 'test-in-function';
34
+ export type DiagnosticCode = 'unresolved-test-import' | 'parse-error' | 'read-error' | 'framework-mismatch' | 'unresolved-tag' | 'unresolved-annotation' | 'unresolved-cases' | 'test-in-loop' | 'dynamic-title' | 'duplicate-title' | 'duplicate-id' | 'internal-error' | 'invalid-chain' | 'skip-without-body' | 'test-without-body' | 'describe-not-called' | 'async-describe' | 'nested-test' | 'tag-without-at' | 'removed-api' | 'only-in-skipped-describe' | 'config-may-change-state' | 'symlink-ignored' | 'invalid-import' | 'globals-not-enabled' | 'unknown-framework-version' | 'unsupported-framework-version' | 'local-test-object' | 'state-in-helper' | 'unresolved-option' | 'dynamic-reason' | 'no-files-matched' | 'unsupported-file' | 'approximate-framework-version' | 'test-in-function' | 'empty-title' | 'bench-outside-benchmark-file';
35
35
  export type MetaValue = string | number | boolean | null | MetaValue[] | {
36
36
  [key: string]: MetaValue;
37
37
  };
@@ -45,18 +45,22 @@ export interface Inventory {
45
45
  /** Read from the project, or given with `--framework-version`; null when unknown. */
46
46
  frameworkVersion: string | null;
47
47
  summary: Summary;
48
+ /** One per scanned file, in the order the files were scanned. */
49
+ files: FileRecord[];
48
50
  suites: SuiteRecord[];
49
51
  tests: TestRecord[];
50
52
  diagnostics: Diagnostic[];
51
53
  }
52
54
  /**
53
55
  * One line of the JSON Lines output (`--format jsonl`): the inventory with each record on its own line, marked by
54
- * `type`. The `inventory` line comes first, then the suites, tests and diagnostics in the order of the JSON output,
55
- * and the `summary` line last.
56
+ * `type`. The `inventory` line comes first, then the files, suites, tests and diagnostics in the order of the JSON
57
+ * output, and the `summary` line last.
56
58
  */
57
59
  export type InventoryLine = ({
58
60
  type: 'inventory';
59
61
  } & Pick<Inventory, 'schemaVersion' | 'tool' | 'framework' | 'frameworkVersion'>) | ({
62
+ type: 'file';
63
+ } & FileRecord) | ({
60
64
  type: 'suite';
61
65
  } & SuiteRecord) | ({
62
66
  type: 'test';
@@ -92,12 +96,38 @@ export interface Summary {
92
96
  inConditionCount: Count;
93
97
  inFunctionCount: Count;
94
98
  typeTestCount: Count;
99
+ benchmarkCount: Count;
95
100
  diagnosticCount: Count;
96
101
  /** Tests per tag. */
97
102
  tagCounts: Record<string, Count>;
98
103
  /** Tests per annotation type. */
99
104
  annotationCounts: Record<string, Count>;
100
105
  }
106
+ /** A scanned file, also one that has no tests or could not be read. */
107
+ export interface FileRecord {
108
+ /** Path from the project root, with `/` separators. */
109
+ relativeFilePath: string;
110
+ fileName: string;
111
+ /** Hooks at the top level of the file, which run around every test in it. */
112
+ hooks: HookCounts;
113
+ suiteCount: Count;
114
+ testCount: Count;
115
+ }
116
+ /**
117
+ * How many hooks of each kind are registered, including by helper functions called there.
118
+ *
119
+ * @inline
120
+ */
121
+ export interface HookCounts {
122
+ beforeAll: Count;
123
+ beforeEach: Count;
124
+ afterEach: Count;
125
+ afterAll: Count;
126
+ /** Vitest only. */
127
+ aroundEach: Count;
128
+ /** Vitest only. */
129
+ aroundAll: Count;
130
+ }
101
131
  /** A describe block, with what is written on the describe itself. Inherited values are on the tests. */
102
132
  export interface SuiteRecord {
103
133
  id: Hash;
@@ -158,6 +188,21 @@ export interface SuiteRecord {
158
188
  locks: string[];
159
189
  /** Vitest only; literal values only. */
160
190
  meta: Record<string, MetaValue> | null;
191
+ /** Hooks registered directly in the describe. */
192
+ hooks: HookCounts;
193
+ /** In milliseconds; null when nothing here sets it. */
194
+ timeout: Count | null;
195
+ /** Playwright `test.slow()` written in the describe, which triples the timeout of its tests. */
196
+ isSlow: boolean;
197
+ /** Source text of the `test.slow()` condition; null when unconditional or not slow. */
198
+ slowCondition: string | null;
199
+ retries: Count | null;
200
+ /** Vitest only: milliseconds between retries, from the `retry` object (4.1). */
201
+ retryDelay: Count | null;
202
+ /** Vitest only: source text of the `retry` object's `condition`, a RegExp or a function. */
203
+ retryCondition: string | null;
204
+ /** Vitest only: how many times the runner runs each test again after the first run. */
205
+ repeats: Count | null;
161
206
  }
162
207
  /** A test, with the effective values the runner applies, including those inherited from its describes. */
163
208
  export interface TestRecord {
@@ -226,6 +271,42 @@ export interface TestRecord {
226
271
  locks: string[];
227
272
  /** Merged from the describes and the test. Vitest only; literal values only. */
228
273
  meta: Record<string, MetaValue> | null;
274
+ /** Every hook that runs around the test: those of the file and of each describe around it. */
275
+ hooks: HookCounts;
276
+ /**
277
+ * In milliseconds: the last `test.setTimeout()` in the body or a `beforeEach`, otherwise the nearest describe or file
278
+ * that sets one. Null when the file sets none, so the config's timeout applies.
279
+ */
280
+ timeout: Count | null;
281
+ /** Playwright `test.slow()` applies: the runner triples the timeout. */
282
+ isSlow: boolean;
283
+ /** Source text of the condition of the `test.slow()` that applies; null when unconditional or not slow. */
284
+ slowCondition: string | null;
285
+ /** How many times the runner retries the test when it fails; null when the file sets none. */
286
+ retries: Count | null;
287
+ /** Vitest only: milliseconds between retries, from the `retry` object (4.1). */
288
+ retryDelay: Count | null;
289
+ /** Vitest only: source text of the `retry` object's `condition`, a RegExp or a function. */
290
+ retryCondition: string | null;
291
+ /** Vitest only: how many times the runner runs the test again after the first run. */
292
+ repeats: Count | null;
293
+ /**
294
+ * Names the test function takes from its context, then those of the `beforeEach`, `afterEach` and `aroundEach` hooks
295
+ * around it, once each. Vitest's own context keys, such as `expect` and `task`, are left out.
296
+ */
297
+ fixtures: string[];
298
+ /** Calls of `expect()`, `expect.soft()` and `expect.poll()` written in the body, each counted once. */
299
+ expectCount: Count;
300
+ /** Vitest `expect.assertions(n)` in the body. */
301
+ expectedAssertions: Count | null;
302
+ /** Vitest `expect.hasAssertions()` in the body. */
303
+ expectsAssertions: boolean;
304
+ /** The test function has no statements, comments aside. */
305
+ hasEmptyBody: boolean;
306
+ /** Playwright `test.step()` and `test.step.skip()` calls in the body, in source order. */
307
+ steps: Step[];
308
+ /** Vitest 5 benchmark: in a benchmark file, or using the `bench` fixture. Plain `vitest` doesn't run it. */
309
+ isBenchmark: boolean;
229
310
  /** Declared with `.each` or `.for`, or inside a describe declared with them, so the runner repeats it. */
230
311
  isParameterized: boolean;
231
312
  /**
@@ -241,6 +322,17 @@ export interface TestRecord {
241
322
  isInFunction: boolean;
242
323
  }
243
324
  /** @inline */
325
+ export interface Step {
326
+ /** The title, or its source text when it can't be worked out. */
327
+ title: string;
328
+ hasDynamicTitle: boolean;
329
+ lineStart: Position;
330
+ /** 0 for a step directly in the test, 1 for a step inside it, and so on. */
331
+ depth: Count;
332
+ /** Declared with `test.step.skip()`. */
333
+ isSkipped: boolean;
334
+ }
335
+ /** @inline */
244
336
  export interface DeclaredAt {
245
337
  /** The helper's file, from the project root. */
246
338
  relativeFilePath: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "test-inventory",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Test metadata from source code, not from test results.",
5
5
  "keywords": [
6
6
  "testing",
package/schema/v1.json CHANGED
@@ -28,6 +28,13 @@
28
28
  "summary": {
29
29
  "$ref": "#/definitions/Summary"
30
30
  },
31
+ "files": {
32
+ "type": "array",
33
+ "items": {
34
+ "$ref": "#/definitions/FileRecord"
35
+ },
36
+ "description": "One per scanned file, in the order the files were scanned."
37
+ },
31
38
  "suites": {
32
39
  "type": "array",
33
40
  "items": {
@@ -53,6 +60,7 @@
53
60
  "framework",
54
61
  "frameworkVersion",
55
62
  "summary",
63
+ "files",
56
64
  "suites",
57
65
  "tests",
58
66
  "diagnostics"
@@ -166,6 +174,10 @@
166
174
  "type": "integer",
167
175
  "minimum": 0
168
176
  },
177
+ "benchmarkCount": {
178
+ "type": "integer",
179
+ "minimum": 0
180
+ },
169
181
  "diagnosticCount": {
170
182
  "type": "integer",
171
183
  "minimum": 0
@@ -206,12 +218,85 @@
206
218
  "inConditionCount",
207
219
  "inFunctionCount",
208
220
  "typeTestCount",
221
+ "benchmarkCount",
209
222
  "diagnosticCount",
210
223
  "tagCounts",
211
224
  "annotationCounts"
212
225
  ],
213
226
  "description": "Counts over the whole scan. Each test count uses the same definition as the matching test key."
214
227
  },
228
+ "FileRecord": {
229
+ "type": "object",
230
+ "properties": {
231
+ "relativeFilePath": {
232
+ "type": "string",
233
+ "description": "Path from the project root, with `/` separators."
234
+ },
235
+ "fileName": {
236
+ "type": "string"
237
+ },
238
+ "hooks": {
239
+ "$ref": "#/definitions/HookCounts",
240
+ "description": "Hooks at the top level of the file, which run around every test in it."
241
+ },
242
+ "suiteCount": {
243
+ "type": "integer",
244
+ "minimum": 0
245
+ },
246
+ "testCount": {
247
+ "type": "integer",
248
+ "minimum": 0
249
+ }
250
+ },
251
+ "required": [
252
+ "relativeFilePath",
253
+ "fileName",
254
+ "hooks",
255
+ "suiteCount",
256
+ "testCount"
257
+ ],
258
+ "description": "A scanned file, also one that has no tests or could not be read."
259
+ },
260
+ "HookCounts": {
261
+ "type": "object",
262
+ "properties": {
263
+ "beforeAll": {
264
+ "type": "integer",
265
+ "minimum": 0
266
+ },
267
+ "beforeEach": {
268
+ "type": "integer",
269
+ "minimum": 0
270
+ },
271
+ "afterEach": {
272
+ "type": "integer",
273
+ "minimum": 0
274
+ },
275
+ "afterAll": {
276
+ "type": "integer",
277
+ "minimum": 0
278
+ },
279
+ "aroundEach": {
280
+ "type": "integer",
281
+ "minimum": 0,
282
+ "description": "Vitest only."
283
+ },
284
+ "aroundAll": {
285
+ "type": "integer",
286
+ "minimum": 0,
287
+ "description": "Vitest only."
288
+ }
289
+ },
290
+ "required": [
291
+ "beforeAll",
292
+ "beforeEach",
293
+ "afterEach",
294
+ "afterAll",
295
+ "aroundEach",
296
+ "aroundAll"
297
+ ],
298
+ "description": "How many hooks of each kind are registered, including by helper functions called there."
299
+ },
215
300
  "SuiteRecord": {
216
301
  "type": "object",
217
302
  "properties": {
@@ -384,6 +469,75 @@
384
469
  }
385
470
  ],
386
471
  "description": "Vitest only; literal values only."
472
+ },
473
+ "hooks": {
474
+ "$ref": "#/definitions/HookCounts",
475
+ "description": "Hooks registered directly in the describe."
476
+ },
477
+ "timeout": {
478
+ "anyOf": [
479
+ {
480
+ "type": "integer",
481
+ "minimum": 0
482
+ },
483
+ {
484
+ "type": "null"
485
+ }
486
+ ],
487
+ "description": "In milliseconds; null when nothing here sets it."
488
+ },
489
+ "isSlow": {
490
+ "type": "boolean",
491
+ "description": "Playwright `test.slow()` written in the describe, which triples the timeout of its tests."
492
+ },
493
+ "slowCondition": {
494
+ "type": [
495
+ "string",
496
+ "null"
497
+ ],
498
+ "description": "Source text of the `test.slow()` condition; null when unconditional or not slow."
499
+ },
500
+ "retries": {
501
+ "anyOf": [
502
+ {
503
+ "type": "integer",
504
+ "minimum": 0
505
+ },
506
+ {
507
+ "type": "null"
508
+ }
509
+ ]
510
+ },
511
+ "retryDelay": {
512
+ "anyOf": [
513
+ {
514
+ "type": "integer",
515
+ "minimum": 0
516
+ },
517
+ {
518
+ "type": "null"
519
+ }
520
+ ],
521
+ "description": "Vitest only: milliseconds between retries, from the `retry` object (4.1)."
522
+ },
523
+ "retryCondition": {
524
+ "type": [
525
+ "string",
526
+ "null"
527
+ ],
528
+ "description": "Vitest only: source text of the `retry` object's `condition`, a RegExp or a function."
529
+ },
530
+ "repeats": {
531
+ "anyOf": [
532
+ {
533
+ "type": "integer",
534
+ "minimum": 0
535
+ },
536
+ {
537
+ "type": "null"
538
+ }
539
+ ],
540
+ "description": "Vitest only: how many times the runner runs each test again after the first run."
387
541
  }
388
542
  },
389
543
  "required": [
@@ -417,7 +571,15 @@
417
571
  "tags",
418
572
  "annotations",
419
573
  "locks",
420
- "meta"
574
+ "meta",
575
+ "hooks",
576
+ "timeout",
577
+ "isSlow",
578
+ "slowCondition",
579
+ "retries",
580
+ "retryDelay",
581
+ "retryCondition",
582
+ "repeats"
421
583
  ],
422
584
  "description": "A describe block, with what is written on the describe itself. Inherited values are on the tests."
423
585
  },
@@ -708,6 +870,119 @@
708
870
  ],
709
871
  "description": "Merged from the describes and the test. Vitest only; literal values only."
710
872
  },
873
+ "hooks": {
874
+ "$ref": "#/definitions/HookCounts",
875
+ "description": "Every hook that runs around the test: those of the file and of each describe around it."
876
+ },
877
+ "timeout": {
878
+ "anyOf": [
879
+ {
880
+ "type": "integer",
881
+ "minimum": 0
882
+ },
883
+ {
884
+ "type": "null"
885
+ }
886
+ ],
887
+ "description": "In milliseconds: the last `test.setTimeout()` in the body or a `beforeEach`, otherwise the nearest describe or file that sets one. Null when the file sets none, so the config's timeout applies."
888
+ },
889
+ "isSlow": {
890
+ "type": "boolean",
891
+ "description": "Playwright `test.slow()` applies: the runner triples the timeout."
892
+ },
893
+ "slowCondition": {
894
+ "type": [
895
+ "string",
896
+ "null"
897
+ ],
898
+ "description": "Source text of the condition of the `test.slow()` that applies; null when unconditional or not slow."
899
+ },
900
+ "retries": {
901
+ "anyOf": [
902
+ {
903
+ "type": "integer",
904
+ "minimum": 0
905
+ },
906
+ {
907
+ "type": "null"
908
+ }
909
+ ],
910
+ "description": "How many times the runner retries the test when it fails; null when the file sets none."
911
+ },
912
+ "retryDelay": {
913
+ "anyOf": [
914
+ {
915
+ "type": "integer",
916
+ "minimum": 0
917
+ },
918
+ {
919
+ "type": "null"
920
+ }
921
+ ],
922
+ "description": "Vitest only: milliseconds between retries, from the `retry` object (4.1)."
923
+ },
924
+ "retryCondition": {
925
+ "type": [
926
+ "string",
927
+ "null"
928
+ ],
929
+ "description": "Vitest only: source text of the `retry` object's `condition`, a RegExp or a function."
930
+ },
931
+ "repeats": {
932
+ "anyOf": [
933
+ {
934
+ "type": "integer",
935
+ "minimum": 0
936
+ },
937
+ {
938
+ "type": "null"
939
+ }
940
+ ],
941
+ "description": "Vitest only: how many times the runner runs the test again after the first run."
942
+ },
943
+ "fixtures": {
944
+ "type": "array",
945
+ "items": {
946
+ "type": "string"
947
+ },
948
+ "description": "Names the test function takes from its context, then those of the `beforeEach`, `afterEach` and `aroundEach` hooks around it, once each. Vitest's own context keys, such as `expect` and `task`, are left out."
949
+ },
950
+ "expectCount": {
951
+ "type": "integer",
952
+ "minimum": 0,
953
+ "description": "Calls of `expect()`, `expect.soft()` and `expect.poll()` written in the body, each counted once."
954
+ },
955
+ "expectedAssertions": {
956
+ "anyOf": [
957
+ {
958
+ "type": "integer",
959
+ "minimum": 0
960
+ },
961
+ {
962
+ "type": "null"
963
+ }
964
+ ],
965
+ "description": "Vitest `expect.assertions(n)` in the body."
966
+ },
967
+ "expectsAssertions": {
968
+ "type": "boolean",
969
+ "description": "Vitest `expect.hasAssertions()` in the body."
970
+ },
971
+ "hasEmptyBody": {
972
+ "type": "boolean",
973
+ "description": "The test function has no statements, comments aside."
974
+ },
975
+ "steps": {
976
+ "type": "array",
977
+ "items": {
978
+ "$ref": "#/definitions/Step"
979
+ },
980
+ "description": "Playwright `test.step()` and `test.step.skip()` calls in the body, in source order."
981
+ },
982
+ "isBenchmark": {
983
+ "type": "boolean",
984
+ "description": "Vitest 5 benchmark: in a benchmark file, or using the `bench` fixture. Plain `vitest` doesn't run it."
985
+ },
711
986
  "isParameterized": {
712
987
  "type": "boolean",
713
988
  "description": "Declared with `.each` or `.for`, or inside a describe declared with them, so the runner repeats it."
@@ -775,6 +1050,21 @@
775
1050
  "comments",
776
1051
  "locks",
777
1052
  "meta",
1053
+ "hooks",
1054
+ "timeout",
1055
+ "isSlow",
1056
+ "slowCondition",
1057
+ "retries",
1058
+ "retryDelay",
1059
+ "retryCondition",
1060
+ "repeats",
1061
+ "fixtures",
1062
+ "expectCount",
1063
+ "expectedAssertions",
1064
+ "expectsAssertions",
1065
+ "hasEmptyBody",
1066
+ "steps",
1067
+ "isBenchmark",
778
1068
  "isParameterized",
779
1069
  "caseCount",
780
1070
  "isInLoop",
@@ -818,6 +1108,38 @@
818
1108
  }
819
1109
  ]
820
1110
  },
1111
+ "Step": {
1112
+ "type": "object",
1113
+ "properties": {
1114
+ "title": {
1115
+ "type": "string",
1116
+ "description": "The title, or its source text when it can't be worked out."
1117
+ },
1118
+ "hasDynamicTitle": {
1119
+ "type": "boolean"
1120
+ },
1121
+ "lineStart": {
1122
+ "type": "integer",
1123
+ "minimum": 1
1124
+ },
1125
+ "depth": {
1126
+ "type": "integer",
1127
+ "minimum": 0,
1128
+ "description": "0 for a step directly in the test, 1 for a step inside it, and so on."
1129
+ },
1130
+ "isSkipped": {
1131
+ "type": "boolean",
1132
+ "description": "Declared with `test.step.skip()`."
1133
+ }
1134
+ },
1135
+ "required": [
1136
+ "title",
1137
+ "hasDynamicTitle",
1138
+ "lineStart",
1139
+ "depth",
1140
+ "isSkipped"
1141
+ ]
1142
+ },
821
1143
  "Diagnostic": {
822
1144
  "type": "object",
823
1145
  "properties": {
@@ -928,7 +1250,9 @@
928
1250
  "no-files-matched",
929
1251
  "unsupported-file",
930
1252
  "approximate-framework-version",
931
- "test-in-function"
1253
+ "test-in-function",
1254
+ "empty-title",
1255
+ "bench-outside-benchmark-file"
932
1256
  ]
933
1257
  },
934
1258
  {