Skip to content

Commit 583dd8a

Browse files
authored
feat(vitest)!: add "vitest list" API to print collected tests without running them (#6013)
1 parent f645e48 commit 583dd8a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+815
-108
lines changed

docs/advanced/pool.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { ProcessPool, WorkspaceProject } from 'vitest/node'
4545
export interface ProcessPool {
4646
name: string
4747
runTests: (files: [project: WorkspaceProject, testFile: string][], invalidates?: string[]) => Promise<void>
48+
collectTests: (files: [project: WorkspaceProject, testFile: string][], invalidates?: string[]) => Promise<void>
4849
close?: () => Promise<void>
4950
}
5051
```
@@ -57,6 +58,8 @@ Vitest will wait until `runTests` is executed before finishing a run (i.e., it w
5758

5859
If you are using a custom pool, you will have to provide test files and their results yourself - you can reference [`vitest.state`](https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/state.ts) for that (most important are `collectFiles` and `updateTasks`). Vitest uses `startTests` function from `@vitest/runner` package to do that.
5960

61+
Vitest will call `collectTests` if `vitest.collect` is called or `vitest list` is invoked via a CLI command. It works the same way as `runTests`, but you don't have to run test callbacks, only report their tasks by calling `vitest.state.collectFiles(files)`.
62+
6063
To communicate between different processes, you can create methods object using `createMethodsRPC` from `vitest/node`, and use any form of communication that you prefer. For example, to use WebSockets with `birpc` you can write something like this:
6164

6265
```ts

docs/guide/cli.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@ export default {
5555

5656
Run only [benchmark](https://vitest.dev/guide/features.html#benchmarking-experimental) tests, which compare performance results.
5757

58+
### `vitest init`
59+
60+
`vitest init <name>` can be used to setup project configuration. At the moment, it only supports [`browser`](/guide/browser) value:
61+
62+
```bash
63+
vitest init browser
64+
```
65+
66+
### `vitest list`
67+
68+
`vitest list` command inherits all `vitest` options to print the list of all matching tests. This command ignores `reporters` option. By default, it will print the names of all tests that matched the file filter and name pattern:
69+
70+
```shell
71+
vitest list filename.spec.ts -t="some-test"
72+
```
73+
74+
```txt
75+
describe > some-test
76+
describe > some-test > test 1
77+
describe > some-test > test 2
78+
```
79+
80+
You can pass down `--json` flag to print tests in JSON format or save it in a separate file:
81+
82+
```bash
83+
vitest list filename.spec.ts -t="some-test" --json=./file.json
84+
```
85+
86+
If `--json` flag doesn't receive a value, it will output the JSON into stdout.
87+
5888
## Options
5989

6090
<!--@include: ./cli-table.md-->

packages/browser/src/client/tester/tester.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SpyModule, setupCommonEnv, startTests } from 'vitest/browser'
1+
import { SpyModule, collectTests, setupCommonEnv, startTests } from 'vitest/browser'
22
import { getBrowserState, getConfig, getWorkerState } from '../utils'
33
import { channel, client, onCancel } from '../client'
44
import { setupDialogsSpy } from './dialog'
@@ -65,8 +65,6 @@ async function prepareTestEnvironment(files: string[]) {
6565
runner,
6666
config,
6767
state,
68-
setupCommonEnv,
69-
startTests,
7068
}
7169
}
7270

@@ -78,7 +76,7 @@ function done(files: string[]) {
7876
})
7977
}
8078

81-
async function runTests(files: string[]) {
79+
async function executeTests(method: 'run' | 'collect', files: string[]) {
8280
await client.waitForConnection()
8381

8482
debug('client is connected to ws server')
@@ -107,7 +105,7 @@ async function runTests(files: string[]) {
107105

108106
debug('runner resolved successfully')
109107

110-
const { config, runner, state, setupCommonEnv, startTests } = preparedData
108+
const { config, runner, state } = preparedData
111109

112110
state.durations.prepare = performance.now() - state.durations.prepare
113111

@@ -116,7 +114,12 @@ async function runTests(files: string[]) {
116114
try {
117115
await setupCommonEnv(config)
118116
for (const file of files) {
119-
await startTests([file], runner)
117+
if (method === 'run') {
118+
await startTests([file], runner)
119+
}
120+
else {
121+
await collectTests([file], runner)
122+
}
120123
}
121124
}
122125
finally {
@@ -127,4 +130,6 @@ async function runTests(files: string[]) {
127130
}
128131

129132
// @ts-expect-error untyped global for internal use
130-
window.__vitest_browser_runner__.runTests = runTests
133+
window.__vitest_browser_runner__.runTests = files => executeTests('run', files)
134+
// @ts-expect-error untyped global for internal use
135+
window.__vitest_browser_runner__.collectTests = files => executeTests('collect', files)

packages/browser/src/node/pool.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
1010
const providers = new Set<BrowserProvider>()
1111

1212
const waitForTests = async (
13+
method: 'run' | 'collect',
1314
contextId: string,
1415
project: WorkspaceProject,
1516
files: string[],
1617
) => {
17-
const context = project.browser!.state.createAsyncContext(contextId, files)
18+
const context = project.browser!.state.createAsyncContext(method, contextId, files)
1819
return await context
1920
}
2021

21-
const runTests = async (project: WorkspaceProject, files: string[]) => {
22+
const executeTests = async (method: 'run' | 'collect', project: WorkspaceProject, files: string[]) => {
2223
ctx.state.clearFiles(project, files)
2324
const browser = project.browser!
2425

@@ -67,13 +68,13 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
6768
contextId,
6869
[...files.map(f => relative(project.config.root, f))].join(', '),
6970
)
70-
const promise = waitForTests(contextId, project, files)
71+
const promise = waitForTests(method, contextId, project, files)
7172
promises.push(promise)
7273
orchestrator.createTesters(files)
7374
}
7475
else {
7576
const contextId = crypto.randomUUID()
76-
const waitPromise = waitForTests(contextId, project, files)
77+
const waitPromise = waitForTests(method, contextId, project, files)
7778
debug?.(
7879
'Opening a new context %s for files: %s',
7980
contextId,
@@ -91,7 +92,7 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
9192
await Promise.all(promises)
9293
}
9394

94-
const runWorkspaceTests = async (specs: [WorkspaceProject, string][]) => {
95+
const runWorkspaceTests = async (method: 'run' | 'collect', specs: [WorkspaceProject, string][]) => {
9596
const groupedFiles = new Map<WorkspaceProject, string[]>()
9697
for (const [project, file] of specs) {
9798
const files = groupedFiles.get(project) || []
@@ -110,7 +111,7 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
110111
break
111112
}
112113

113-
await runTests(project, files)
114+
await executeTests(method, project, files)
114115
}
115116
}
116117

@@ -140,6 +141,7 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
140141
await Promise.all([...providers].map(provider => provider.close()))
141142
providers.clear()
142143
},
143-
runTests: runWorkspaceTests,
144+
runTests: files => runWorkspaceTests('run', files),
145+
collectTests: files => runWorkspaceTests('collect', files),
144146
}
145147
}

packages/browser/src/node/serverTester.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ export async function resolveTester(
2929
? '__vitest_browser_runner__.files'
3030
: JSON.stringify([testFile])
3131
const iframeId = JSON.stringify(testFile)
32-
const files = state.getContext(contextId)?.files ?? []
32+
const context = state.getContext(contextId)
33+
const files = context?.files ?? []
34+
const method = context?.method ?? 'run'
3335

3436
const injectorJs = typeof server.injectorJs === 'string'
3537
? server.injectorJs
@@ -74,7 +76,7 @@ export async function resolveTester(
7476
`<script type="module">
7577
__vitest_browser_runner__.runningFiles = ${tests}
7678
__vitest_browser_runner__.iframeId = ${iframeId}
77-
__vitest_browser_runner__.runTests(__vitest_browser_runner__.runningFiles)
79+
__vitest_browser_runner__.${method === 'run' ? 'runTests' : 'collectTests'}(__vitest_browser_runner__.runningFiles)
7880
</script>`,
7981
})
8082
}

packages/browser/src/node/state.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ export class BrowserServerState implements IBrowserServerState {
1414
return this.contexts.get(contextId)
1515
}
1616

17-
createAsyncContext(contextId: string, files: string[]): Promise<void> {
17+
createAsyncContext(method: 'run' | 'collect', contextId: string, files: string[]): Promise<void> {
1818
const defer = createDefer<void>()
1919
this.contexts.set(contextId, {
2020
files,
21+
method,
2122
resolve: () => {
2223
defer.resolve()
2324
this.contexts.delete(contextId)

packages/runner/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { startTests, updateTask } from './run'
1+
export { startTests, updateTask, collectTests } from './run'
22
export {
33
test,
44
it,

packages/runner/src/run.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,3 +512,14 @@ export async function startTests(paths: string[], runner: VitestRunner) {
512512

513513
return files
514514
}
515+
516+
async function publicCollect(paths: string[], runner: VitestRunner) {
517+
await runner.onBeforeCollect?.(paths)
518+
519+
const files = await collectTests(paths, runner)
520+
521+
await runner.onCollected?.(files)
522+
return files
523+
}
524+
525+
export { publicCollect as collectTests }

packages/vitest/LICENSE.md

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -438,27 +438,6 @@ License: MIT
438438
By: Mathias Bynens
439439
Repository: https://github.com/mathiasbynens/emoji-regex.git
440440

441-
> Copyright Mathias Bynens <https://mathiasbynens.be/>
442-
>
443-
> Permission is hereby granted, free of charge, to any person obtaining
444-
> a copy of this software and associated documentation files (the
445-
> "Software"), to deal in the Software without restriction, including
446-
> without limitation the rights to use, copy, modify, merge, publish,
447-
> distribute, sublicense, and/or sell copies of the Software, and to
448-
> permit persons to whom the Software is furnished to do so, subject to
449-
> the following conditions:
450-
>
451-
> The above copyright notice and this permission notice shall be
452-
> included in all copies or substantial portions of the Software.
453-
>
454-
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
455-
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
456-
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
457-
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
458-
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
459-
> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
460-
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
461-
462441
---------------------------------------
463442

464443
## expect-type

packages/vitest/src/browser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { startTests, processError } from '@vitest/runner'
1+
export { startTests, collectTests, processError } from '@vitest/runner'
22
export {
33
setupCommonEnv,
44
loadDiffConfig,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy