Skip to content

Commit

Permalink
feat(cli): Extend existing list command to output only a list of file…
Browse files Browse the repository at this point in the history
… names (#6392)

Co-authored-by: Vladimir <sleuths.slews0s@icloud.com>
  • Loading branch information
Ma-hawaj and sheremet-va authored Aug 29, 2024
1 parent 122e4fe commit 008f00b
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 12 deletions.
11 changes: 11 additions & 0 deletions docs/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ vitest list filename.spec.ts -t="some-test" --json=./file.json

If `--json` flag doesn't receive a value, it will output the JSON into stdout.

You also can pass down `--filesOnly` flag to print the test files only:

```bash
vitest list --filesOnly
```

```txt
tests/test1.test.ts
tests/test2.test.ts
```

## Options

::: tip
Expand Down
29 changes: 29 additions & 0 deletions packages/vitest/LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,35 @@ Repository: sindresorhus/p-locate
---------------------------------------

## package-manager-detector
License: MIT
By: Anthony Fu
Repository: git+https://github.com/antfu-collective/package-manager-detector.git

> MIT License
>
> Copyright (c) 2020-PRESENT Anthony Fu <https://github.com/antfu>
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in all
> copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> SOFTWARE.
---------------------------------------

## picomatch
License: MIT
By: Jon Schlinkert
Expand Down
26 changes: 16 additions & 10 deletions packages/vitest/src/node/cli/cac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,24 +300,30 @@ async function collect(mode: VitestRunMode, cliFilters: string[], options: CliOp
catch {}

try {
const { prepareVitest, processCollected } = await import('./cli-api')
const { prepareVitest, processCollected, outputFileList } = await import('./cli-api')
const ctx = await prepareVitest(mode, {
...normalizeCliOptions(options),
watch: false,
run: true,
})
if (!options.filesOnly) {
const { tests, errors } = await ctx.collect(cliFilters.map(normalize))

if (errors.length) {
console.error('\nThere were unhandled errors during test collection')
errors.forEach(e => console.error(e))
console.error('\n\n')
await ctx.close()
return
}

const { tests, errors } = await ctx.collect(cliFilters.map(normalize))

if (errors.length) {
console.error('\nThere were unhandled errors during test collection')
errors.forEach(e => console.error(e))
console.error('\n\n')
await ctx.close()
return
processCollected(ctx, tests, options)
}
else {
const files = await ctx.listFiles(cliFilters.map(normalize))
outputFileList(files, options)
}

processCollected(ctx, tests, options)
await ctx.close()
}
catch (e) {
Expand Down
49 changes: 48 additions & 1 deletion packages/vitest/src/node/cli/cli-api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-console */

import { mkdirSync, writeFileSync } from 'node:fs'
import { dirname, resolve } from 'pathe'
import { dirname, relative, resolve } from 'pathe'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { File, Suite, Task } from '@vitest/runner'
import { CoverageProviderMap } from '../../integrations/coverage'
Expand All @@ -12,6 +12,7 @@ import type { Vitest, VitestOptions } from '../core'
import { FilesNotFoundError, GitNotFoundError } from '../errors'
import { getNames, getTests } from '../../utils'
import type { UserConfig, VitestEnvironment, VitestRunMode } from '../types/config'
import type { WorkspaceSpec } from '../pool'

export interface CliOptions extends UserConfig {
/**
Expand All @@ -26,6 +27,10 @@ export interface CliOptions extends UserConfig {
* Output collected tests as JSON or to a file
*/
json?: string | boolean
/**
* Output collected test files only
*/
filesOnly?: boolean
}

/**
Expand Down Expand Up @@ -184,6 +189,48 @@ export function processCollected(ctx: Vitest, files: File[], options: CliOptions
return formatCollectedAsString(files).forEach(test => console.log(test))
}

export function outputFileList(files: WorkspaceSpec[], options: CliOptions) {
if (typeof options.json !== 'undefined') {
return outputJsonFileList(files, options)
}

return formatFilesAsString(files, options).map(file => console.log(file))
}

function outputJsonFileList(files: WorkspaceSpec[], options: CliOptions) {
if (typeof options.json === 'boolean') {
return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2))
}
if (typeof options.json === 'string') {
const jsonPath = resolve(options.root || process.cwd(), options.json)
mkdirSync(dirname(jsonPath), { recursive: true })
writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2))
}
}

function formatFilesAsJSON(files: WorkspaceSpec[]) {
return files.map((file) => {
const result: any = {
file: file.moduleId,
}

if (file.project.name) {
result.projectName = file.project.name
}
return result
})
}

function formatFilesAsString(files: WorkspaceSpec[], options: CliOptions) {
return files.map((file) => {
let name = relative(options.root || process.cwd(), file.moduleId)
if (file.project.name) {
name = `[${file.project.name}] ${name}`
}
return name
})
}

function processJsonOutput(files: File[], options: CliOptions) {
if (typeof options.json === 'boolean') {
return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2))
Expand Down
6 changes: 5 additions & 1 deletion packages/vitest/src/node/cli/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ export const cliOptionsConfig: VitestCLIOptions = {
outputJson: null,
json: null,
provide: null,
filesOnly: null,
}

export const benchCliOptionsConfig: Pick<
Expand All @@ -813,10 +814,13 @@ export const benchCliOptionsConfig: Pick<

export const collectCliOptionsConfig: Pick<
VitestCLIOptions,
'json'
'json' | 'filesOnly'
> = {
json: {
description: 'Print collected tests as JSON or write to a file (Default: false)',
argument: '[true/path]',
},
filesOnly: {
description: 'Print only test files with out the test cases',
},
}
8 changes: 8 additions & 0 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,14 @@ export class Vitest {
}
}

async listFiles(filters?: string[]) {
const files = await this.filterTestsBySource(
await this.globTestFiles(filters),
)

return files
}

async start(filters?: string[]) {
this._onClose = []

Expand Down
66 changes: 66 additions & 0 deletions test/cli/test/list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ test('correctly outputs json', async () => {
expect(exitCode).toBe(0)
})

test('correctly outputs files only json', async () => {
const { stdout, exitCode } = await runVitestCli('list', '-r=./fixtures/list', '--json', '--filesOnly')
expect(relative(stdout)).toMatchInlineSnapshot(`
"[
{
"file": "<root>/fixtures/list/basic.test.ts"
},
{
"file": "<root>/fixtures/list/math.test.ts"
}
]
"
`)
expect(exitCode).toBe(0)
})

test('correctly saves json', async () => {
const { stdout, exitCode } = await runVitestCli('list', '-r=./fixtures/list', '--json=./list.json')
onTestFinished(() => {
Expand Down Expand Up @@ -96,6 +112,26 @@ test('correctly saves json', async () => {
expect(exitCode).toBe(0)
})

test('correctly saves files only json', async () => {
const { stdout, exitCode } = await runVitestCli('list', '-r=./fixtures/list', '--json=./list.json', '--filesOnly')
onTestFinished(() => {
rmSync('./fixtures/list/list.json')
})
const json = readFileSync('./fixtures/list/list.json', 'utf-8')
expect(stdout).toBe('')
expect(relative(json)).toMatchInlineSnapshot(`
"[
{
"file": "<root>/fixtures/list/basic.test.ts"
},
{
"file": "<root>/fixtures/list/math.test.ts"
}
]"
`)
expect(exitCode).toBe(0)
})

test('correctly filters by file', async () => {
const { stdout, exitCode } = await runVitestCli('list', 'math.test.ts', '-r=./fixtures/list')
expect(stdout).toMatchInlineSnapshot(`
Expand All @@ -106,6 +142,15 @@ test('correctly filters by file', async () => {
expect(exitCode).toBe(0)
})

test('correctly filters by file when using --filesOnly', async () => {
const { stdout, exitCode } = await runVitestCli('list', 'math.test.ts', '-r=./fixtures/list', '--filesOnly')
expect(stdout).toMatchInlineSnapshot(`
"math.test.ts
"
`)
expect(exitCode).toBe(0)
})

test('correctly prints project name in basic report', async () => {
const { stdout } = await runVitestCli('list', 'math.test.ts', '-r=./fixtures/list', '--config=./custom.config.ts')
expect(stdout).toMatchInlineSnapshot(`
Expand All @@ -115,6 +160,14 @@ test('correctly prints project name in basic report', async () => {
`)
})

test('correctly prints project name in basic report when using --filesOnly', async () => {
const { stdout } = await runVitestCli('list', 'math.test.ts', '-r=./fixtures/list', '--config=./custom.config.ts', '--filesOnly')
expect(stdout).toMatchInlineSnapshot(`
"[custom] math.test.ts
"
`)
})

test('correctly prints project name and locations in json report', async () => {
const { stdout } = await runVitestCli('list', 'math.test.ts', '-r=./fixtures/list', '--json', '--config=./custom.config.ts')
expect(relative(stdout)).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -142,6 +195,19 @@ test('correctly prints project name and locations in json report', async () => {
`)
})

test('correctly prints project name in json report when using --filesOnly', async () => {
const { stdout } = await runVitestCli('list', 'math.test.ts', '-r=./fixtures/list', '--json', '--config=./custom.config.ts', '--filesOnly')
expect(relative(stdout)).toMatchInlineSnapshot(`
"[
{
"file": "<root>/fixtures/list/math.test.ts",
"projectName": "custom"
}
]
"
`)
})

test('correctly filters by test name', async () => {
const { stdout } = await runVitestCli('list', '-t=inner', '-r=./fixtures/list')
expect(stdout).toMatchInlineSnapshot(`
Expand Down

0 comments on commit 008f00b

Please sign in to comment.