test-inventory 0.7.0 → 0.9.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 +180 -0
- package/README.md +16 -10
- package/dist/case-titles.d.ts +22 -0
- package/dist/case-titles.js +184 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +5 -5
- package/dist/config-dependencies.js +27 -3
- package/dist/config-runs.d.ts +117 -3
- package/dist/config-runs.js +1015 -19
- package/dist/config.d.ts +42 -1
- package/dist/config.js +287 -21
- package/dist/dependency-hash.d.ts +13 -5
- package/dist/dependency-hash.js +56 -12
- package/dist/diagnostics.js +16 -1
- package/dist/extract.d.ts +2 -0
- package/dist/extract.js +89 -29
- package/dist/files.js +4 -2
- package/dist/filter.js +1 -0
- package/dist/framework-version.d.ts +13 -2
- package/dist/framework-version.js +207 -7
- package/dist/frameworks/bindings.d.ts +14 -0
- package/dist/frameworks/bindings.js +99 -6
- package/dist/frameworks/bun.d.ts +42 -0
- package/dist/frameworks/bun.js +272 -0
- package/dist/frameworks/common.d.ts +3 -1
- package/dist/frameworks/common.js +18 -9
- package/dist/frameworks/cypress.d.ts +31 -0
- package/dist/frameworks/cypress.js +70 -0
- package/dist/frameworks/jasmine.d.ts +28 -0
- package/dist/frameworks/jasmine.js +218 -0
- package/dist/frameworks/jest.d.ts +46 -0
- package/dist/frameworks/jest.js +442 -0
- package/dist/frameworks/mocha.d.ts +50 -0
- package/dist/frameworks/mocha.js +306 -0
- package/dist/frameworks/node.d.ts +30 -0
- package/dist/frameworks/node.js +268 -0
- package/dist/frameworks/playwright.d.ts +13 -0
- package/dist/frameworks/playwright.js +57 -0
- package/dist/frameworks/test-functions.d.ts +194 -0
- package/dist/frameworks/test-functions.js +534 -0
- package/dist/frameworks/vitest.d.ts +15 -62
- package/dist/frameworks/vitest.js +69 -389
- package/dist/frameworks/webdriverio.d.ts +27 -0
- package/dist/frameworks/webdriverio.js +37 -0
- package/dist/imported-values.js +15 -1
- package/dist/model.d.ts +9 -2
- package/dist/node-scripts.d.ts +6 -0
- package/dist/node-scripts.js +85 -0
- package/dist/options.d.ts +16 -3
- package/dist/options.js +22 -3
- package/dist/parse.js +17 -2
- package/dist/records.d.ts +8 -2
- package/dist/records.js +94 -22
- package/dist/resolve.d.ts +21 -4
- package/dist/resolve.js +91 -52
- package/dist/scan-file.d.ts +8 -0
- package/dist/scan-file.js +21 -3
- package/dist/scan.js +62 -12
- package/dist/toml.d.ts +13 -0
- package/dist/toml.js +172 -0
- package/dist/types.d.ts +27 -11
- package/dist/values.d.ts +15 -0
- package/dist/values.js +120 -2
- package/dist/yaml.d.ts +12 -0
- package/dist/yaml.js +148 -0
- package/package.json +7 -6
- package/schema/v1.json +30 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,185 @@
|
|
|
1
1
|
# test-inventory
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#88](https://github.com/Huldoser/test-inventory/pull/88) [`2d370c9`](https://github.com/Huldoser/test-inventory/commit/2d370c9030c5fafae900d2442d75e70781a5b938) - Bun 1.2.23 and newer: `--framework bun`, also found from a package.json script that runs `bun test` or a
|
|
8
|
+
`bunfig.toml`. Its version comes from `.bun-version`, `packageManager` or `engines.bun`, else `@types/bun` or
|
|
9
|
+
`bun-types`. The scan reads Bun's globals and imports of `bun:test`, `@jest/globals` and `vitest`, which Bun rewrites;
|
|
10
|
+
chains of `.skip`, `.todo`, `.failing`, `.only`, `.concurrent`, `.serial` and `.each` in any order, refusing the
|
|
11
|
+
combinations Bun refuses; the conditions `.if`, `.skipIf`, `.todoIf`, `.failingIf`, `.concurrentIf` and `.serialIf`;
|
|
12
|
+
options second or third, a number as the timeout or `{ timeout, retry, repeats }`; and `.each` titles as Bun formats
|
|
13
|
+
them. The files are Bun's `*.test.*`, `*_test.*`, `*.spec.*` and `*_spec.*` under `bunfig.toml`'s `[test] root`, less
|
|
14
|
+
`pathIgnorePatterns`, with its `retry` and `concurrentTestGlob` applied. A small TOML reader reads `bunfig.toml`.
|
|
15
|
+
|
|
16
|
+
The oldest version a framework supports may now name a patch, as Bun's 1.2.23 does.
|
|
17
|
+
|
|
18
|
+
- [#87](https://github.com/Huldoser/test-inventory/pull/87) [`ae2bd90`](https://github.com/Huldoser/test-inventory/commit/ae2bd909d769ea5e21200fceb3d9f081de7661db) - `dependencyHash` follows imports through the config a file runs with: Vite's `resolve.alias` and Vitest's
|
|
19
|
+
`test.alias`, as an object or a list of `{ find, replacement }` with a name or a regex, and Jest's `moduleNameMapper`,
|
|
20
|
+
`modulePaths` and `moduleDirectories`, with `<rootDir>`. They were read from tsconfig `paths` only, so tests that
|
|
21
|
+
imported through such aliases had `hasUnfollowedDependencies` and a hash that missed those files. A mapping to no file
|
|
22
|
+
is a `dependency-not-followed` warning that names it.
|
|
23
|
+
|
|
24
|
+
- [#83](https://github.com/Huldoser/test-inventory/pull/83) [`9ef9c59`](https://github.com/Huldoser/test-inventory/commit/9ef9c5959b908191e8015c8c880a3c476f43fccd) - Cypress 13 and newer: `--framework cypress`, also found from a `cypress` package or a `cypress.config.*` file. Tests are
|
|
25
|
+
read as Mocha's, with Cypress's test config before the function: `retries`, of which `cypress run` takes `runMode`,
|
|
26
|
+
`browser` as a skip condition, `@cypress/grep`'s `tags`, and from Cypress 16 an error for `env`, which Cypress refuses
|
|
27
|
+
there. `this.timeout()` is not read, as Cypress has only command timeouts; `this.retries()` in a describe and
|
|
28
|
+
`.retries()` after `it()` or `describe()` are errors, as Cypress throws on them while it loads the spec. The config's
|
|
29
|
+
testing types are the projects, `e2e` and `component`, each with its `specPattern`, `excludeSpecPattern` and `retries`.
|
|
30
|
+
|
|
31
|
+
A project whose package.json lists `cypress` next to another runner, as Jest or Vitest for unit tests, now needs
|
|
32
|
+
`--framework`, as the scan asks for one whenever it finds several runners.
|
|
33
|
+
|
|
34
|
+
- [#82](https://github.com/Huldoser/test-inventory/pull/82) [`04e7328`](https://github.com/Huldoser/test-inventory/commit/04e73289dd946bd4c92ec774510ebc369ee80699) - Jasmine 4 and newer: `--framework jasmine`, also found from a `jasmine` or `karma-jasmine` package or a
|
|
35
|
+
`spec/support/jasmine.*` config. The scan reads `describe`, `it` and their `x` and `f` forms with Jasmine's focus, a
|
|
36
|
+
spec without a function as pending, `pending(reason)` in a spec or its `beforeEach` or `afterEach`, from Jasmine 7
|
|
37
|
+
`notApplicable(reason)`, the hooks, and a spec's timeout. The config's `spec_dir` and `spec_files`, with `!`
|
|
38
|
+
exclusions, decide the files; without a config, as in Karma and Angular projects, the files given by glob run. A call
|
|
39
|
+
Jasmine refuses stops the whole run at the top level of a file, and is an error that leaves the file's tests as they
|
|
40
|
+
are inside a describe, which Jasmine catches.
|
|
41
|
+
|
|
42
|
+
- [#81](https://github.com/Huldoser/test-inventory/pull/81) [`85fb8a9`](https://github.com/Huldoser/test-inventory/commit/85fb8a90998f88641400ebb8a6db3b392e2b54d2) - Mocha 10 and newer: `--framework mocha`, also found from a `mocha` package, a `.mocharc.*` file or a `mocha` key in
|
|
43
|
+
`package.json`. The scan reads `describe`, `context`, `it`, `specify`, their `x` forms, `.only` and `.skip`, a test
|
|
44
|
+
without a function as pending, `ui: tdd`'s `suite` and `test`, the hooks, `this.timeout()`, `this.retries()` and
|
|
45
|
+
`this.skip()` where `this` is Mocha's, and `.timeout()` and `.retries()` after `it()` and `describe()`. The config's
|
|
46
|
+
`spec`, `extension`, `recursive`, `ignore` and `file` decide the files, and its `timeout` and `retries` apply to every
|
|
47
|
+
test; a YAML config is read too. A describe without a function, `it()` or `describe()` without a title, and an
|
|
48
|
+
unknown chain such as `it.concurrent` are errors, as Mocha then runs no test.
|
|
49
|
+
|
|
50
|
+
A project whose package.json lists `mocha` next to another runner now needs `--framework`, as the scan asks for one
|
|
51
|
+
whenever it finds several runners.
|
|
52
|
+
|
|
53
|
+
- [#86](https://github.com/Huldoser/test-inventory/pull/86) [`1085fb7`](https://github.com/Huldoser/test-inventory/commit/1085fb74b85eefe64c6bdd217b2c19c2946441d4) - node:test on Node.js 22 and newer: `--framework node`, also found from a package.json script that runs `node --test`
|
|
54
|
+
or a `node.config.json`. Its version is the Node.js version the project pins in `.node-version`, `.nvmrc`, Volta's
|
|
55
|
+
`node` or `engines.node`. The scan reads `test`, `it`, `describe` and `suite` from `node:test`, imported or required,
|
|
56
|
+
with `.skip`, `.todo`, `.only` and from 24.14 `.expectFailure`, and the options `skip`, `todo`, `only`, `timeout`,
|
|
57
|
+
`concurrency`, `expectFailure` and from 24.19 and 26.2 `tags`; `t.skip()` and `t.todo()` in a test's body; and the
|
|
58
|
+
hooks. The files are those the script gives `node --test`, or Node.js's default patterns, with TypeScript files from
|
|
59
|
+
22.18.
|
|
60
|
+
|
|
61
|
+
A test declared in a test's body, with `t.test()` or `test()`, is a subtest that node:test runs while it runs the test:
|
|
62
|
+
it is listed with the test's title in `suitePath` and the test's id in the new key `parentTestId`, which is `null` for
|
|
63
|
+
every other test.
|
|
64
|
+
|
|
65
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - A new `invalid-fixture-argument` error: a rest property among a Playwright function's fixture arguments, as
|
|
66
|
+
`async ({ page, ...fixtures }) => {}` in a test, hook, `test.skip()` condition or `test.extend()` fixture written in
|
|
67
|
+
the test file. Playwright refuses it and runs no tests at all, so the file's tests are now `notLoaded` instead of
|
|
68
|
+
`active`. A nested rest, as `({ page: { mouse, ...pointer } })`, and a `test.step()` callback are allowed, as
|
|
69
|
+
Playwright allows them.
|
|
70
|
+
|
|
71
|
+
- [#85](https://github.com/Huldoser/test-inventory/pull/85) [`90df9aa`](https://github.com/Huldoser/test-inventory/commit/90df9aa07741fab403470e653595b1b644b35dc3) - `scan()` takes a `signal`, an `AbortSignal`: the scan checks it before it starts and between files, and rejects with
|
|
72
|
+
the signal's `reason` once it aborts, so a server can stop a scan its client no longer waits for.
|
|
73
|
+
|
|
74
|
+
- [#85](https://github.com/Huldoser/test-inventory/pull/85) [`90df9aa`](https://github.com/Huldoser/test-inventory/commit/90df9aa07741fab403470e653595b1b644b35dc3) - A Vitest `.only` that `allowOnly` makes fail is a `forbidden-only` diagnostic, as for Playwright's `forbidOnly`: an
|
|
75
|
+
error when the config sets `test.allowOnly` to `false`, and a warning when it is unset, as Vitest then turns it off in
|
|
76
|
+
CI, or depends on a condition. Vitest marks such a test failed instead of running it.
|
|
77
|
+
|
|
78
|
+
- [#84](https://github.com/Huldoser/test-inventory/pull/84) [`c68bac7`](https://github.com/Huldoser/test-inventory/commit/c68bac7442f7d5197c8f67bfbec66a8c9ee3f4d5) - WebdriverIO 9 and newer: `--framework webdriverio`, also found from a `@wdio/cli` package or a `wdio.conf.*` file. The
|
|
79
|
+
config's `config` export, ES or CommonJS, decides the files: `specs`, with the nested lists that group files into one
|
|
80
|
+
worker, less `exclude`, matched as WebdriverIO matches them. Its `framework` decides how the tests are read, Mocha by
|
|
81
|
+
default or Jasmine, with `mochaOpts.timeout`, `retries` and `ui`, or `jasmineOpts.defaultTimeoutInterval`, on every
|
|
82
|
+
test; Cucumber is reported, as its feature files aren't read. A number after a test's function is WebdriverIO's retry
|
|
83
|
+
count, and with Jasmine a second one, after the timeout. Mocha's and Jasmine's version gates follow the versions
|
|
84
|
+
WebdriverIO depends on. With Mocha, a call the runner refuses stops the file loading there, and the tests declared
|
|
85
|
+
above it still run. The config's `rootDir` and each capability's own `specs` and `exclude` are read too.
|
|
86
|
+
|
|
87
|
+
A project whose package.json lists `@wdio/cli` next to another runner now needs `--framework`, as the scan asks for
|
|
88
|
+
one whenever it finds several runners.
|
|
89
|
+
|
|
90
|
+
### Patch Changes
|
|
91
|
+
|
|
92
|
+
- [#85](https://github.com/Huldoser/test-inventory/pull/85) [`90df9aa`](https://github.com/Huldoser/test-inventory/commit/90df9aa07741fab403470e653595b1b644b35dc3) - `expectCount` counts Playwright's `expect.configure(...)`, called in place as `expect.configure({ timeout: 5_000 })(locator)`
|
|
93
|
+
or kept in a variable as `const slowExpect = expect.configure(...)`; it missed both.
|
|
94
|
+
|
|
95
|
+
- [#83](https://github.com/Huldoser/test-inventory/pull/83) [`9ef9c59`](https://github.com/Huldoser/test-inventory/commit/9ef9c5959b908191e8015c8c880a3c476f43fccd) - The error for an unknown `framework` option or `--framework` value names every runner the scan reads; it still named
|
|
96
|
+
only Playwright, Vitest and Jest.
|
|
97
|
+
|
|
98
|
+
- [#89](https://github.com/Huldoser/test-inventory/pull/89) [`fd4b13a`](https://github.com/Huldoser/test-inventory/commit/fd4b13a45ec2349319b5edaec4dd0cbe1170d663) - `--help` names all nine runners `--framework` takes, and says which files node:test and Bun run without globs.
|
|
99
|
+
|
|
100
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - A helper that takes a test's function as a parameter, as `function settlementTest(desk, body) { describe(desk, () =>
|
|
101
|
+
test('settles', body)); }`, no longer gets a false `nested-test` warning. The scan read the parameter as the helper
|
|
102
|
+
itself, and so read the helper's own describe as declared inside the test.
|
|
103
|
+
|
|
104
|
+
- [#78](https://github.com/Huldoser/test-inventory/pull/78) [`1aea8a7`](https://github.com/Huldoser/test-inventory/commit/1aea8a744c955a01f1918447e048046a4eb022b4) - oxc-parser is updated from 0.156.0 to 0.157.0. The scan output doesn't change, except that a `.js` file with
|
|
105
|
+
TypeScript-only syntax, such as `export default abstract class` or an optional class member, now gets a `parse-error`, as
|
|
106
|
+
Node.js would refuse to load it.
|
|
107
|
+
|
|
108
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - A test or describe call with a title the runner refuses, written inside a test or hook body, is now a `nested-test`
|
|
109
|
+
warning, not an error that says the runner fails the file. Jest's own suite calls `it('test1')` inside
|
|
110
|
+
`expect(() => ...)` to test that error; the call runs in the test, so the file loads and its tests run.
|
|
111
|
+
|
|
112
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - Before Vitest 4.1, a `retry` object in the config, as `test: { retry: { count: 2 } }`, now gets a
|
|
113
|
+
`config-value-unknown` warning that Vitest runs no test with it. The tests already had `retries: null`, but nothing
|
|
114
|
+
said why.
|
|
115
|
+
|
|
116
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - A call through a Vitest member that reads the function it is called on, destructured as in
|
|
117
|
+
`const { each } = test; each([1, 2])('sizes lot %i', fn)`, is now an `invalid-chain` error, and the file's tests are
|
|
118
|
+
`notLoaded`: Vitest fails the file. That holds for `each`, `for`, `skipIf` and `runIf` of `test` and `each` of
|
|
119
|
+
`describe` in every version, `extend`, `scoped` and `override` from Vitest 4.1, and `for` of `describe` from Vitest 5.
|
|
120
|
+
Before, the scan said nothing and listed the file's other tests as active.
|
|
121
|
+
|
|
122
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - An inline Vitest project in `test.projects` now runs from the config's `test.root` or `root` when it sets none of its
|
|
123
|
+
own, as every Vitest version does; the scan used the config's folder before Vitest 5. A root the project sets is
|
|
124
|
+
resolved from the config's root in Vitest 5, as Vitest 5 does, and from the config's folder before.
|
|
125
|
+
|
|
126
|
+
- [#85](https://github.com/Huldoser/test-inventory/pull/85) [`90df9aa`](https://github.com/Huldoser/test-inventory/commit/90df9aa07741fab403470e653595b1b644b35dc3) - With `expandCases`, a Vitest case title cuts long values at the length the config sets, `test.taskTitleValueFormatTruncate`
|
|
127
|
+
from Vitest 5 and `test.chaiConfig.truncateThreshold` before, as Vitest does; it cut them at Vitest's default, 40, always.
|
|
128
|
+
|
|
129
|
+
- [#80](https://github.com/Huldoser/test-inventory/pull/80) [`cae53c1`](https://github.com/Huldoser/test-inventory/commit/cae53c107fce5a3024f7666c83d9b2582bb9017b) - From Vitest 5, `timeout: undefined`, `retry: undefined` and `repeats: undefined` in a test's options are left out, as
|
|
130
|
+
Vitest leaves them out, instead of giving an `unresolved-option` warning that `undefined` is not a whole number.
|
|
131
|
+
|
|
132
|
+
## 0.8.0
|
|
133
|
+
|
|
134
|
+
### Minor Changes
|
|
135
|
+
|
|
136
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - `--framework` (library: `framework`) is now optional. Without it, the scan takes the runner the project uses: the one
|
|
137
|
+
whose package a `package.json` in the root or below it lists, or whose config file is there, else one a `package.json`
|
|
138
|
+
above the root lists. A project with several runners, or none, gets a usage error (a `TypeError` in the library) that
|
|
139
|
+
names what it found.
|
|
140
|
+
|
|
141
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - Jest 29 and 30: `--framework jest` (library: `framework: 'jest'`) lists the tests of Jest files with the same keys as
|
|
142
|
+
Playwright and Vitest tests. It reads Jest's globals, `fit`, `xit`, `xtest`, `fdescribe` and `xdescribe` among them,
|
|
143
|
+
imports and `require()` of `@jest/globals`, the chains Jest has, such as `test.concurrent.only.each`, `.failing` as
|
|
144
|
+
`expectedToFail`, the timeout passed third, `jest.retryTimes()` as `retries` for every test of the file (from 30.5,
|
|
145
|
+
with `entireDescribe`, of its describe) and `waitBeforeRetry` as `retryDelay`, and `@group` pragmas as tags, as
|
|
146
|
+
jest-runner-groups reads them. `--expand-cases` titles each case as jest-each 29 and 30 do. Calls Jest refuses, such
|
|
147
|
+
as `test.only.concurrent`, `test('title')` without a function or an async describe, mark the file's tests `notLoaded`.
|
|
148
|
+
|
|
149
|
+
Without globs, the test files come from the Jest config, read as Jest reads it: `jest.config.*`, else `package.json`,
|
|
150
|
+
with `roots`, `testMatch`, `testRegex`, the ignore patterns, `moduleFileExtensions`, `projects` named by
|
|
151
|
+
`displayName`, `testTimeout` and `injectGlobals`, also through Jest 30.3's `defineConfig()` and `mergeConfig()`;
|
|
152
|
+
without any config, Jest's defaults apply. `framework` in the output
|
|
153
|
+
can now be `jest`, an open set, so `schemaVersion` stays 1.
|
|
154
|
+
|
|
155
|
+
The `cases-not-expanded` message no longer names Vitest, as Jest tables can get it too.
|
|
156
|
+
|
|
157
|
+
### Patch Changes
|
|
158
|
+
|
|
159
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - `require()` of a local file is followed as an import is: tables, titles and other values it exports, with
|
|
160
|
+
`module.exports` or `exports.name`, are read, and helper functions it exports that declare tests are followed. A
|
|
161
|
+
helper function a shared file imports and exports again, as an `index.js` of helpers does, is followed to where it is
|
|
162
|
+
written, instead of getting an `unresolved-test-import` error. A helpers file may export a test function it takes from
|
|
163
|
+
the runner's globals, as `export const pendingTest = xit`, or from the framework's module, with its modifiers.
|
|
164
|
+
|
|
165
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - A call the runner refuses, such as `test.only.skip(...)`, that is only reached under a condition no longer marks every
|
|
166
|
+
test of its file `notLoaded`, as the file loads unless the condition holds; the call is still reported. A test function
|
|
167
|
+
chosen with `&&`, `||` or `??`, as in `const onCi = process.env.CI && test.skip || test`, is read like one chosen with
|
|
168
|
+
`?:`. In a config, a list with a spread the scan can't work out keeps the items it can.
|
|
169
|
+
|
|
170
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - A config that `require()`s a local file, as a CommonJS config does with a shared base, now reads what that file
|
|
171
|
+
exports, as an `import` of it already did, and a JSON file, required or imported, is read as its value.
|
|
172
|
+
|
|
173
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - A table or loop gets its `caseCount` when its length is known even if one of its values isn't, as in
|
|
174
|
+
`[NaN, Infinity].forEach(...)` or a table with a call in a row. A test or describe titled by a function or class
|
|
175
|
+
written in place, as `describe(function OrderBook() {}, ...)`, takes its name, as the runners do. Code the parser
|
|
176
|
+
fails to hand over, such as a JSX name written as a Unicode escape, gets a `parse-error` instead of an
|
|
177
|
+
`internal-error`.
|
|
178
|
+
|
|
179
|
+
- [#75](https://github.com/Huldoser/test-inventory/pull/75) [`f6690bb`](https://github.com/Huldoser/test-inventory/commit/f6690bbe5e49ce048ec4169f21bed23f702942d1) - `dependencyHash` is faster on large projects: the files a test file and its describes reach are put together once for
|
|
180
|
+
all their tests, and a workspace's packages are found once, not once per folder that imports one. A scan of the Nx
|
|
181
|
+
repository with 17,571 tests went from 19.4 to 11.9 seconds. Hashes are unchanged.
|
|
182
|
+
|
|
3
183
|
## 0.7.0
|
|
4
184
|
|
|
5
185
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Test metadata from source code, not from test results.
|
|
4
4
|
|
|
5
|
-
test-inventory reads Playwright
|
|
6
|
-
lines, the describes around it, its tags and annotations, and
|
|
7
|
-
to fail or in a file the runner refuses to load, with the condition
|
|
8
|
-
the
|
|
5
|
+
test-inventory reads Playwright, Vitest, Jest, Mocha, Jasmine, Cypress, WebdriverIO, node:test and Bun test files and
|
|
6
|
+
lists every test declaration as JSON: its title, file and lines, the describes around it, its tags and annotations, and
|
|
7
|
+
whether it is active, skipped, fixme, todo, expected to fail or in a file the runner refuses to load, with the condition
|
|
8
|
+
when the state only applies sometimes. Each test has an id that survives a move to another line and a hash of everything
|
|
9
|
+
it runs, from its hooks and fixtures to its page objects, test data, snapshots and config, so it can also list the tests
|
|
10
|
+
a change can affect. It parses the code and runs nothing, so it needs no browsers, no build and no runner configuration.
|
|
9
11
|
|
|
10
12
|
Documentation: [huldoser.github.io/test-inventory](https://huldoser.github.io/test-inventory/)
|
|
11
13
|
|
|
@@ -15,7 +17,9 @@ Documentation: [huldoser.github.io/test-inventory](https://huldoser.github.io/te
|
|
|
15
17
|
npm install --save-dev test-inventory
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
Node.js 22.12 or newer, on Linux, macOS or Windows. Playwright 1.42 or newer, Vitest 3.0 or newer.
|
|
20
|
+
Node.js 22.12 or newer, on Linux, macOS or Windows. Playwright 1.42 or newer, Vitest 3.0 or newer, Jest 29.0 or newer,
|
|
21
|
+
Mocha 10.0 or newer, Jasmine 4.0 or newer, Cypress 13.0 or newer, WebdriverIO 9.0 or newer, node:test 22.0 or newer,
|
|
22
|
+
Bun 1.2.23 or newer.
|
|
19
23
|
|
|
20
24
|
## Command line
|
|
21
25
|
|
|
@@ -25,7 +29,9 @@ Node.js 22.12 or newer, on Linux, macOS or Windows. Playwright 1.42 or newer, Vi
|
|
|
25
29
|
npx test-inventory "tests/**/*.spec.ts" --framework playwright --output inventory.json
|
|
26
30
|
```
|
|
27
31
|
|
|
28
|
-
Without the glob, the test files are those the Playwright
|
|
32
|
+
Without the glob, the test files are those the project's Playwright, Vitest, Jest, Mocha, Jasmine, Cypress or
|
|
33
|
+
WebdriverIO configs run, or for node:test and Bun the files `node --test` and `bun test` run. Without `--framework`, the
|
|
34
|
+
scan takes the runner the project uses, and asks for `--framework` when it uses several.
|
|
29
35
|
|
|
30
36
|
For this spec from a trading app's UI tests, `tests/alerts.spec.ts`:
|
|
31
37
|
|
|
@@ -98,12 +104,12 @@ in Claude Code, Cursor, VS Code and other MCP clients ask it which tests a proje
|
|
|
98
104
|
|
|
99
105
|
- Config files are read as code, never run, and only in part: settings computed at run time, as from `process.env`,
|
|
100
106
|
can't be worked out, and settings such as `workers` or `use` are not read.
|
|
101
|
-
- Values
|
|
102
|
-
that names the module. A custom `test` object is followed through as many files as it takes, through relative
|
|
103
|
-
paths, tsconfig path aliases, `#` imports in package.json and workspace packages; one that can't be followed gets
|
|
107
|
+
- Values from installed packages are not worked out; values from the project's own files are. A tag or title that
|
|
108
|
+
comes from a package gets a diagnostic that names the module. A custom `test` object is followed through as many files as it takes, through relative
|
|
109
|
+
paths, config and tsconfig path aliases, `#` imports in package.json and workspace packages; one that can't be followed gets
|
|
104
110
|
an error. Tests declared in helper functions are listed at each call, also for helpers imported from other files.
|
|
105
111
|
- A test in a loop or a `.each` table is one record, with `isInLoop` or `caseCount`; the runner creates one test per
|
|
106
|
-
iteration or case.
|
|
112
|
+
iteration or case. `--expand-cases` lists each case whose values the scan can work out as its own record.
|
|
107
113
|
- Conditions such as `browserName === 'webkit'` are kept as source text, not evaluated.
|
|
108
114
|
|
|
109
115
|
## Support
|
package/dist/case-titles.d.ts
CHANGED
|
@@ -12,3 +12,25 @@ import type { Value } from './values.ts';
|
|
|
12
12
|
* values whole.
|
|
13
13
|
*/
|
|
14
14
|
export declare function vitestCaseTitle(template: string, items: readonly Value[], index: number, version: readonly [number, number] | null, truncate?: number): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* The title Jest gives one row of a `.each` table of arrays, or of single values, read from `jest-each` 29.0, 29.7,
|
|
17
|
+
* 30.0 and 30.5: `%#` and from 30.0 `%$` for the row's index, then one placeholder per item, in order. `%p` shows the
|
|
18
|
+
* item with pretty-format and the others with Node's `util.format`, which Jest calls too. Items left over are dropped.
|
|
19
|
+
* Null when an item is an array or object that `util.format` would show, which differs between Node versions.
|
|
20
|
+
*/
|
|
21
|
+
export declare function jestRowTitle(template: string, row: readonly Value[], index: number, version: readonly [number, number] | null): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* The title Jest gives one case of a `.each` table of objects, or one row of a tagged-template table: `$name` and
|
|
24
|
+
* `$name.path` for the case's values, and `$#` for its index. `keepsEscapes` is set for a tagged template, where `%%`
|
|
25
|
+
* stays as written. Null when Jest fails the table, as when a path goes through `null` before 30.0.
|
|
26
|
+
*/
|
|
27
|
+
export declare function jestKeysTitle(template: string, item: Record<string, Value>, index: number, version: readonly [number, number] | null, keepsEscapes: boolean): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* The title Bun gives one case of `.each`, read from Bun 1.2.23, 1.3.14 and 1.4.4: for a case whose first value is an
|
|
30
|
+
* object, first `$key` and `$key.path` for its values, then for every case the placeholders, left to right. `%s` takes
|
|
31
|
+
* a string, `%d` and `%f` a number, `%i` an integer, `%j` and `%o` any value as JSON; a value of another type leaves
|
|
32
|
+
* the placeholder as written, but is used up. `%#` is the index, `%%` a `%`, and `%` before any other character is
|
|
33
|
+
* dropped. Once the values are used up, the rest stays as written. Null where Bun pretty-prints: `%p`, and `$key`
|
|
34
|
+
* of an object, `null` or `undefined`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function bunCaseTitle(template: string, args: readonly Value[], index: number, version: readonly [number, number] | null): string | null;
|
package/dist/case-titles.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { format } from 'node:util';
|
|
1
2
|
/**
|
|
2
3
|
* The title Vitest gives one case of a `.each` or `.for` table, read from Vitest's `formatTitle` in 3.0, 3.1, 4.1
|
|
3
4
|
* and 5.0: `%#` and `%$` for the case's index, printf placeholders for its items, and `$name` for a key of its object.
|
|
@@ -225,3 +226,186 @@ function loupeTruncate(text, length) {
|
|
|
225
226
|
end -= 1;
|
|
226
227
|
return `${text.slice(0, end)}…`;
|
|
227
228
|
}
|
|
229
|
+
/** The text Jest puts in place of `%%` and of `%` in string values while it formats a title. */
|
|
230
|
+
const JEST_ESCAPE = '@@__JEST_EACH_PLACEHOLDER_ESCAPE__@@';
|
|
231
|
+
const JEST_PLACEHOLDER = /%[#Odfijops]/;
|
|
232
|
+
/** The placeholders `util.format` takes an argument for. */
|
|
233
|
+
const NODE_PLACEHOLDER = /%[sdifjoOc]/;
|
|
234
|
+
/**
|
|
235
|
+
* The title Jest gives one row of a `.each` table of arrays, or of single values, read from `jest-each` 29.0, 29.7,
|
|
236
|
+
* 30.0 and 30.5: `%#` and from 30.0 `%$` for the row's index, then one placeholder per item, in order. `%p` shows the
|
|
237
|
+
* item with pretty-format and the others with Node's `util.format`, which Jest calls too. Items left over are dropped.
|
|
238
|
+
* Null when an item is an array or object that `util.format` would show, which differs between Node versions.
|
|
239
|
+
*/
|
|
240
|
+
export function jestRowTitle(template, row, index, version) {
|
|
241
|
+
const isJest30 = version === null || version[0] >= 30;
|
|
242
|
+
const replacesWithFunction = version === null || version[0] > 30 || (version[0] === 30 && version[1] >= 5);
|
|
243
|
+
let text = template.replaceAll('%%', JEST_ESCAPE).replace('%#', String(index));
|
|
244
|
+
if (isJest30)
|
|
245
|
+
text = text.replace('%$', String(index + 1));
|
|
246
|
+
for (const item of row) {
|
|
247
|
+
const placeholder = JEST_PLACEHOLDER.exec(text);
|
|
248
|
+
if (placeholder === null)
|
|
249
|
+
continue;
|
|
250
|
+
const value = typeof item === 'string' ? item.replaceAll('%', JEST_ESCAPE) : item;
|
|
251
|
+
if (placeholder[0] === '%p') {
|
|
252
|
+
const pretty = prettyFormatMin(value);
|
|
253
|
+
// Before 30.5, `$&` and the like in the value are read as replacement patterns, as JavaScript's `replace` does.
|
|
254
|
+
text = replacesWithFunction ? text.replace('%p', () => pretty) : text.replace('%p', pretty);
|
|
255
|
+
}
|
|
256
|
+
else if (placeholder[0] === '%j' && replacesWithFunction) {
|
|
257
|
+
const json = value === undefined ? 'undefined' : JSON.stringify(value);
|
|
258
|
+
text = text.replace('%j', () => json);
|
|
259
|
+
}
|
|
260
|
+
else if (isPrimitive(value) || (placeholder[0] === '%j' && NODE_PLACEHOLDER.exec(text)?.[0] === '%j')) {
|
|
261
|
+
text = format(text, value);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return text.replaceAll(JEST_ESCAPE, '%');
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* The title Jest gives one case of a `.each` table of objects, or one row of a tagged-template table: `$name` and
|
|
271
|
+
* `$name.path` for the case's values, and `$#` for its index. `keepsEscapes` is set for a tagged template, where `%%`
|
|
272
|
+
* stays as written. Null when Jest fails the table, as when a path goes through `null` before 30.0.
|
|
273
|
+
*/
|
|
274
|
+
export function jestKeysTitle(template, item, index, version, keepsEscapes) {
|
|
275
|
+
let text;
|
|
276
|
+
try {
|
|
277
|
+
text = interpolateKeys(template, item, version);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
const title = text.replace('$#', String(index));
|
|
283
|
+
return keepsEscapes ? title : title.replaceAll('%%', '%');
|
|
284
|
+
}
|
|
285
|
+
/** Jest's `interpolateVariables`, which throws where Jest's does. */
|
|
286
|
+
function interpolateKeys(template, item, version) {
|
|
287
|
+
const [major, minor] = version ?? [Infinity, 0];
|
|
288
|
+
const show = (value) => (isPrimitive(value) ? String(value) : prettyFormatMin(value));
|
|
289
|
+
if (major === 29 && minor < 4) {
|
|
290
|
+
// Each match of each key is replaced in turn, as text, so a value can hold the next key's match.
|
|
291
|
+
const matches = Object.keys(item).flatMap((key) => template.match(new RegExp(`\\$${key}[\\.\\w]*`, 'g')) ?? []);
|
|
292
|
+
return matches.reduce((title, match) => title.replace(match, show(keyPath(item, match, false))), template);
|
|
293
|
+
}
|
|
294
|
+
let keys = Object.keys(item);
|
|
295
|
+
if (major > 30 || (major === 30 && minor >= 5)) {
|
|
296
|
+
keys = keys.filter((key) => key.length > 0).sort((a, b) => b.length - a.length);
|
|
297
|
+
if (keys.length === 0)
|
|
298
|
+
return template;
|
|
299
|
+
keys = keys.map((key) => key.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&'));
|
|
300
|
+
}
|
|
301
|
+
const pattern = new RegExp(`\\$(${keys.join('|')})[.\\w]*`, 'g');
|
|
302
|
+
return template.replaceAll(pattern, (match) => show(keyPath(item, match, major >= 30)));
|
|
303
|
+
}
|
|
304
|
+
/** The value a `$name.path` match leads to, as Jest's `getPath` reads it; from 30.0 `null` and `undefined` end it. */
|
|
305
|
+
function keyPath(item, match, endsAtNull) {
|
|
306
|
+
let value = item;
|
|
307
|
+
for (const key of match.slice(1).split('.')) {
|
|
308
|
+
if (endsAtNull && (value === null || value === undefined))
|
|
309
|
+
return String(value);
|
|
310
|
+
// Throws on `null` and `undefined` before 30.0, as Jest's does.
|
|
311
|
+
if (!key || !Object.prototype.hasOwnProperty.call(value, key))
|
|
312
|
+
return value;
|
|
313
|
+
value = value[key];
|
|
314
|
+
}
|
|
315
|
+
return endsAtNull && (value === null || value === undefined) ? String(value) : value;
|
|
316
|
+
}
|
|
317
|
+
/** pretty-format with `{ min: true, maxDepth: 1 }`, as Jest shows a value in a title. */
|
|
318
|
+
function prettyFormatMin(value, depth = 0) {
|
|
319
|
+
if (typeof value === 'string')
|
|
320
|
+
return `"${value.replaceAll(/"|\\/g, '\\$&')}"`;
|
|
321
|
+
if (isPrimitive(value))
|
|
322
|
+
return Object.is(value, -0) ? '-0' : String(value);
|
|
323
|
+
if (depth >= 1)
|
|
324
|
+
return Array.isArray(value) ? '[Array]' : '[Object]';
|
|
325
|
+
if (Array.isArray(value))
|
|
326
|
+
return `[${value.map((item) => prettyFormatMin(item, depth + 1)).join(', ')}]`;
|
|
327
|
+
const keys = Object.keys(value).sort();
|
|
328
|
+
return `{${keys.map((key) => `${prettyFormatMin(key)}: ${prettyFormatMin(value[key], depth + 1)}`).join(', ')}}`;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* The title Bun gives one case of `.each`, read from Bun 1.2.23, 1.3.14 and 1.4.4: for a case whose first value is an
|
|
332
|
+
* object, first `$key` and `$key.path` for its values, then for every case the placeholders, left to right. `%s` takes
|
|
333
|
+
* a string, `%d` and `%f` a number, `%i` an integer, `%j` and `%o` any value as JSON; a value of another type leaves
|
|
334
|
+
* the placeholder as written, but is used up. `%#` is the index, `%%` a `%`, and `%` before any other character is
|
|
335
|
+
* dropped. Once the values are used up, the rest stays as written. Null where Bun pretty-prints: `%p`, and `$key`
|
|
336
|
+
* of an object, `null` or `undefined`.
|
|
337
|
+
*/
|
|
338
|
+
export function bunCaseTitle(template, args, index, version) {
|
|
339
|
+
let text = template;
|
|
340
|
+
const [first] = args;
|
|
341
|
+
if (first !== null && typeof first === 'object' && !Array.isArray(first)) {
|
|
342
|
+
const quotes = version !== null && (version[0] < 1 || (version[0] === 1 && version[1] < 3));
|
|
343
|
+
const shown = { all: true };
|
|
344
|
+
text = text.replace(/\$([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)/g, (written, path) => {
|
|
345
|
+
let value = first;
|
|
346
|
+
for (const key of path.split('.')) {
|
|
347
|
+
value = value !== null && typeof value === 'object' && !Array.isArray(value) ? value[key] : undefined;
|
|
348
|
+
}
|
|
349
|
+
if (value === undefined && !hasPath(first, path))
|
|
350
|
+
return written;
|
|
351
|
+
if (typeof value === 'string')
|
|
352
|
+
return quotes ? JSON.stringify(value) : value;
|
|
353
|
+
if (typeof value === 'number')
|
|
354
|
+
return Object.is(value, -0) ? '-0' : String(value);
|
|
355
|
+
if (typeof value === 'boolean')
|
|
356
|
+
return String(value);
|
|
357
|
+
shown.all = false;
|
|
358
|
+
return written;
|
|
359
|
+
});
|
|
360
|
+
if (!shown.all)
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
let out = '';
|
|
364
|
+
let used = 0;
|
|
365
|
+
for (let at = 0; at < text.length; at++) {
|
|
366
|
+
const char = text[at];
|
|
367
|
+
if (char !== '%' || at === text.length - 1) {
|
|
368
|
+
out += char;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (used >= args.length)
|
|
372
|
+
return out + text.slice(at);
|
|
373
|
+
const placeholder = text[++at];
|
|
374
|
+
if (placeholder === '#')
|
|
375
|
+
out += String(index);
|
|
376
|
+
else if (placeholder === '%')
|
|
377
|
+
out += '%';
|
|
378
|
+
else if (placeholder === 'p')
|
|
379
|
+
return null;
|
|
380
|
+
else if ('sdfijo'.includes(placeholder)) {
|
|
381
|
+
const formatted = bunValue(placeholder, args[used++]);
|
|
382
|
+
if (formatted === null)
|
|
383
|
+
return null;
|
|
384
|
+
out += formatted;
|
|
385
|
+
}
|
|
386
|
+
else
|
|
387
|
+
out += placeholder;
|
|
388
|
+
}
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
/** Whether an object has a value at a dotted path, `undefined` included. */
|
|
392
|
+
function hasPath(item, path) {
|
|
393
|
+
let value = item;
|
|
394
|
+
for (const key of path.split('.')) {
|
|
395
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value) || !(key in value))
|
|
396
|
+
return false;
|
|
397
|
+
value = value[key];
|
|
398
|
+
}
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
/** One placeholder of a Bun title, or the placeholder as written for a value of another type; null for a JSON Bun shows otherwise. */
|
|
402
|
+
function bunValue(placeholder, value) {
|
|
403
|
+
const written = `%${placeholder}`;
|
|
404
|
+
if (placeholder === 's')
|
|
405
|
+
return typeof value === 'string' ? value : written;
|
|
406
|
+
if (placeholder === 'd' || placeholder === 'f')
|
|
407
|
+
return typeof value === 'number' ? String(value) : written;
|
|
408
|
+
if (placeholder === 'i')
|
|
409
|
+
return typeof value === 'number' && Number.isInteger(value) ? String(value) : written;
|
|
410
|
+
return value === undefined ? null : JSON.stringify(value);
|
|
411
|
+
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -6,6 +6,6 @@ export interface Io {
|
|
|
6
6
|
/** Read for `--related -`. */
|
|
7
7
|
stdin?: Readable;
|
|
8
8
|
}
|
|
9
|
-
export declare const HELP = "Usage: test-inventory [glob...]
|
|
9
|
+
export declare const HELP = "Usage: test-inventory [glob...] [options]\n\nLists the tests in the matching files as JSON, read from the source code without running them. Without globs, the\ntest files are those the runner's configs in the root and the folders below it run, or for node:test and Bun those\nnode --test and bun test run.\n\nOptions:\n --framework <name> playwright, vitest, jest, mocha, jasmine, cypress, webdriverio, node or bun\n (default: the one the project uses)\n --root <dir> project root; paths in the output are relative to it (default: current directory)\n --ignore <glob> leave out matching files; can be repeated (node_modules is always left out)\n --framework-version <x.y.z> apply the rules of this framework version instead of the one in the project\n --comments <mode> comments above tests: all, non-active or none (default: non-active)\n --expand-cases one record per case of a .each or .for table and per pass of a loop, with its title\n --state <state> keep tests in this state, such as skip or fixme; can be repeated\n --tag <tag> keep tests with this tag, such as @smoke; can be repeated\n --grep <regex> keep tests whose full name matches, ignoring case\n --only keep tests that use .only, or are inside a describe that does\n --without-reason keep tests that don't run and give no reason\n --related <file> keep tests a change to this file can affect; can be repeated; - reads files, one per\n line, from standard input, as git diff --name-only writes them\n --fields <keys> write only these keys of each test, separated by commas; id is always kept\n --format <format> json or jsonl, one record per line (default: json)\n -o, --output <file> write to a file instead of standard output\n --pretty indent the JSON\n -h, --help show this help\n -v, --version show the version\n\nExit codes: 0 when the scan finishes, even with diagnostics; 2 for invalid arguments, an output that cannot be\nwritten, or a crash. 1 is reserved for a future release.\n\nExamples:\n test-inventory \"tests/**/*.spec.ts\" --framework playwright --output inventory.json\n test-inventory \"tests/**/*.spec.ts\" --framework playwright --state skip --fields fullName,reason\n";
|
|
10
10
|
/** Runs the command line with the given arguments and streams. Resolves to the exit code. */
|
|
11
11
|
export declare function run(argv: string[], io: Io): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -8,13 +8,15 @@ import { writeInventory, writeInventoryLines } from "./json.js";
|
|
|
8
8
|
import { OptionsError, toPosixPath } from "./options.js";
|
|
9
9
|
import { scan } from "./scan.js";
|
|
10
10
|
import { toolVersion } from "./version.js";
|
|
11
|
-
export const HELP = `Usage: test-inventory [glob...]
|
|
11
|
+
export const HELP = `Usage: test-inventory [glob...] [options]
|
|
12
12
|
|
|
13
13
|
Lists the tests in the matching files as JSON, read from the source code without running them. Without globs, the
|
|
14
|
-
test files are those the
|
|
14
|
+
test files are those the runner's configs in the root and the folders below it run, or for node:test and Bun those
|
|
15
|
+
node --test and bun test run.
|
|
15
16
|
|
|
16
17
|
Options:
|
|
17
|
-
--framework <name> playwright or
|
|
18
|
+
--framework <name> playwright, vitest, jest, mocha, jasmine, cypress, webdriverio, node or bun
|
|
19
|
+
(default: the one the project uses)
|
|
18
20
|
--root <dir> project root; paths in the output are relative to it (default: current directory)
|
|
19
21
|
--ignore <glob> leave out matching files; can be repeated (node_modules is always left out)
|
|
20
22
|
--framework-version <x.y.z> apply the rules of this framework version instead of the one in the project
|
|
@@ -143,8 +145,6 @@ export async function run(argv, io) {
|
|
|
143
145
|
io.stdout.write(`${toolVersion}\n`);
|
|
144
146
|
return FINISHED;
|
|
145
147
|
}
|
|
146
|
-
if (values.framework === undefined)
|
|
147
|
-
return fail('--framework is required: playwright or vitest.');
|
|
148
148
|
const format = values.format ?? 'json';
|
|
149
149
|
if (!FORMATS.includes(format))
|
|
150
150
|
return fail('--format must be json or jsonl.');
|
|
@@ -16,6 +16,13 @@ const SNAPSHOT_KEYS = {
|
|
|
16
16
|
['test', 'browser', 'expect', 'toMatchScreenshot', 'resolveScreenshotPath'],
|
|
17
17
|
['test', 'browser', 'expect', 'toMatchScreenshot', 'screenshotDirectory'],
|
|
18
18
|
],
|
|
19
|
+
jest: [['snapshotResolver']],
|
|
20
|
+
mocha: [],
|
|
21
|
+
jasmine: [],
|
|
22
|
+
cypress: [],
|
|
23
|
+
webdriverio: [],
|
|
24
|
+
node: [],
|
|
25
|
+
bun: [],
|
|
19
26
|
};
|
|
20
27
|
/** The keys of a config that name setup files, by framework; Vitest's are a project's own. */
|
|
21
28
|
const SETUP_KEYS = {
|
|
@@ -24,6 +31,20 @@ const SETUP_KEYS = {
|
|
|
24
31
|
['test', 'setupFiles'],
|
|
25
32
|
['test', 'globalSetup'],
|
|
26
33
|
],
|
|
34
|
+
jest: [['setupFiles'], ['setupFilesAfterEnv'], ['globalSetup'], ['globalTeardown']],
|
|
35
|
+
// Mocha loads both before the tests: `require` for root hooks and global fixtures, `file` as test files.
|
|
36
|
+
mocha: [['require'], ['file']],
|
|
37
|
+
// Jasmine's `helpers` are globs from `spec_dir`, which these paths from the config's folder don't cover.
|
|
38
|
+
jasmine: [],
|
|
39
|
+
// The support file Cypress loads before every spec.
|
|
40
|
+
cypress: [
|
|
41
|
+
['e2e', 'supportFile'],
|
|
42
|
+
['component', 'supportFile'],
|
|
43
|
+
],
|
|
44
|
+
// Mocha's `require` runs before the specs, as root hooks may.
|
|
45
|
+
webdriverio: [['mochaOpts', 'require']],
|
|
46
|
+
node: [],
|
|
47
|
+
bun: [],
|
|
27
48
|
};
|
|
28
49
|
const UNKNOWN_PROJECTS = "The projects that run the file can't be worked out, so dependencyHash doesn't cover their setup.";
|
|
29
50
|
/**
|
|
@@ -86,7 +107,9 @@ export class ConfigDependencies {
|
|
|
86
107
|
const found = written(settings, keys);
|
|
87
108
|
for (const item of found ? listOf(found.setting) : []) {
|
|
88
109
|
if (item.kind === 'value' && typeof item.value === 'string') {
|
|
89
|
-
|
|
110
|
+
// Jest's `<rootDir>` at the start of a path is the project's root.
|
|
111
|
+
const file = item.value.startsWith('<rootDir>') ? `.${item.value.slice(9)}` : item.value;
|
|
112
|
+
const read = this.setupFile(root, file);
|
|
90
113
|
if (read && !('reason' in read))
|
|
91
114
|
modules.add(read);
|
|
92
115
|
else if (read) {
|
|
@@ -124,13 +147,14 @@ export class ConfigDependencies {
|
|
|
124
147
|
? projects
|
|
125
148
|
: [{ settings: placement.settings, root: folder, container: null }];
|
|
126
149
|
// Vitest runs the global setup of the config it starts with for every project, extending it or not.
|
|
127
|
-
|
|
150
|
+
if (this.framework === 'vitest')
|
|
151
|
+
setup(own, config.settings, folder, ['test', 'globalSetup']);
|
|
128
152
|
for (const project of running) {
|
|
129
153
|
// A file several projects run may be run by one from another config, which the file runs with too; the config
|
|
130
154
|
// reader has read that config, so it can be read.
|
|
131
155
|
const written = 'config' in project ? this.module(project.config.file) : own;
|
|
132
156
|
modules.add(written);
|
|
133
|
-
for (const keys of SETUP_KEYS.
|
|
157
|
+
for (const keys of SETUP_KEYS[this.framework])
|
|
134
158
|
setup(written, project.settings, project.root, keys);
|
|
135
159
|
const { container } = project;
|
|
136
160
|
const outer = container && this.module(container.file);
|