Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(watch): don't indicate exit when no matching files #7246

Merged
merged 10 commits into from
Jan 15, 2025
14 changes: 5 additions & 9 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { VitestPackageInstaller } from './packageInstaller'
import { createPool } from './pool'
import { TestProject } from './project'
import { BlobReporter, readBlobs } from './reporters/blob'
import { HangingProcessReporter } from './reporters/hanging-process'
import { createBenchmarkReporters, createReporters } from './reporters/utils'
import { VitestSpecifications } from './specifications'
import { StateManager } from './state'
Expand Down Expand Up @@ -564,8 +565,6 @@ export class Vitest {
// Report coverage for uncovered files
await this.reportCoverage(coverage, true)

this.logger.printNoTestFound(filters)

if (throwAnError) {
throw new FilesNotFoundError(this.mode)
}
Expand Down Expand Up @@ -671,11 +670,6 @@ export class Vitest {
}

private async runFiles(specs: TestSpecification[], allTestsRun: boolean): Promise<TestRunResult> {
const filepaths = specs.map(spec => spec.moduleId)
this.state.collectPaths(filepaths)

await this.report('onPathsCollected', filepaths)
await this.report('onSpecsCollected', specs.map(spec => spec.toJSON()))
await this._testRun.start(specs)

// previous run
Expand Down Expand Up @@ -1140,7 +1134,7 @@ export class Vitest {
this.state.getProcessTimeoutCauses().forEach(cause => console.warn(cause))

if (!this.pool) {
const runningServers = [this.vite, ...this.resolvedProjects.map(p => p.vite)].filter(Boolean).length
const runningServers = [this._vite, ...this.resolvedProjects.map(p => p._vite)].filter(Boolean).length

if (runningServers === 1) {
console.warn('Tests closed successfully but something prevents Vite server from exiting')
Expand All @@ -1152,7 +1146,9 @@ export class Vitest {
console.warn('Tests closed successfully but something prevents the main process from exiting')
}

console.warn('You can try to identify the cause by enabling "hanging-process" reporter. See https://vitest.dev/config/#reporters')
if (!this.reporters.some(r => r instanceof HangingProcessReporter)) {
console.warn('You can try to identify the cause by enabling "hanging-process" reporter. See https://vitest.dev/config/#reporters')
}
}

process.exit()
Expand Down
43 changes: 25 additions & 18 deletions packages/vitest/src/node/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,29 @@ export class Logger {

printNoTestFound(filters?: string[]) {
const config = this.ctx.config

if (config.watch && (config.changed || config.related?.length)) {
this.log(`No affected ${config.mode} files found\n`)
}
else if (config.watch) {
this.log(
c.red(`No ${config.mode} files found. You can change the file name pattern by pressing "p"\n`),
)
}
else {
if (config.passWithNoTests) {
this.log(`No ${config.mode} files found, exiting with code 0\n`)
}
else {
this.error(
c.red(`No ${config.mode} files found, exiting with code 1\n`),
)
}
}

const comma = c.dim(', ')
if (filters?.length) {
this.console.error(c.dim('filter: ') + c.yellow(filters.join(comma)))
this.console.error(c.dim('filter: ') + c.yellow(filters.join(comma)))
}
const projectsFilter = toArray(config.project)
if (projectsFilter.length) {
Expand All @@ -140,9 +160,9 @@ export class Logger {
}
this.ctx.projects.forEach((project) => {
const config = project.config
const output = (project.isRootProject() || !project.name) ? '' : `[${project.name}]`
if (output) {
this.console.error(c.bgCyan(`${output} Config`))
const printConfig = !project.isRootProject() && project.name
if (printConfig) {
this.console.error(`\n${formatProjectName(project.name)}\n`)
}
if (config.include) {
this.console.error(
Expand All @@ -165,20 +185,7 @@ export class Logger {
)
}
})

if (config.watch && (config.changed || config.related?.length)) {
this.log(`No affected ${config.mode} files found\n`)
}
else {
if (config.passWithNoTests) {
this.log(`No ${config.mode} files found, exiting with code 0\n`)
}
else {
this.error(
c.red(`\nNo ${config.mode} files found, exiting with code 1`),
)
}
}
this.console.error()
}

printBanner() {
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class TestProject {
/** @internal */ vitenode!: ViteNodeServer
/** @internal */ typechecker?: Typechecker
/** @internal */ _config?: ResolvedConfig
/** @internal */ _vite?: ViteDevServer

private runner!: ViteNodeRunner

Expand All @@ -75,7 +76,6 @@ export class TestProject {

private _globalSetups?: GlobalSetupFile[]
private _provided: ProvidedContext = {} as any
private _vite?: ViteDevServer

constructor(
/** @deprecated */
Expand Down
7 changes: 6 additions & 1 deletion packages/vitest/src/node/reporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ export abstract class BaseReporter implements Reporter {

onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
this.end = performance.now()
this.reportSummary(files, errors)
if (!files.length && !errors.length) {
this.ctx.logger.printNoTestFound(this.ctx.filenamePattern)
}
else {
this.reportSummary(files, errors)
}
}

onTaskUpdate(packs: TaskResultPack[]) {
Expand Down
18 changes: 7 additions & 11 deletions packages/vitest/src/node/reporters/default.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { File } from '@vitest/runner'
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { BaseOptions } from './base'
import type { ReportedHookContext, TestCase, TestModule } from './reported-tasks'
import { BaseReporter } from './base'
Expand Down Expand Up @@ -29,6 +29,10 @@ export class DefaultReporter extends BaseReporter {
}
}

onTestRunStart(specifications: ReadonlyArray<TestSpecification>) {
this.summary?.onTestRunStart(specifications)
}

onTestModuleQueued(file: TestModule) {
this.summary?.onTestModuleQueued(file)
}
Expand Down Expand Up @@ -72,17 +76,9 @@ export class DefaultReporter extends BaseReporter {
this.renderSucceed = paths.length <= 1
}
}

this.summary?.onPathsCollected(paths)
}

onWatcherRerun(files: string[], trigger?: string) {
this.summary?.onWatcherRerun()
super.onWatcherRerun(files, trigger)
}

onFinished(files?: File[], errors?: unknown[]) {
this.summary?.onFinished()
super.onFinished(files, errors)
onTestRunEnd() {
this.summary?.onTestRunEnd()
}
}
2 changes: 1 addition & 1 deletion packages/vitest/src/node/reporters/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class JsonReporter implements Reporter {
const numTodoTests = tests.filter(t => t.mode === 'todo').length
const testResults: Array<JsonTestResult> = []

const success = numFailedTestSuites === 0 && numFailedTests === 0
const success = !!(files.length > 0 || this.ctx.config.passWithNoTests) && numFailedTestSuites === 0 && numFailedTests === 0

for (const file of files) {
const tests = getTests([file])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class WindowRenderer {

start() {
this.finished = false
this.renderInterval = setInterval(() => this.flushBuffer(), this.options.interval)
this.renderInterval = setInterval(() => this.flushBuffer(), this.options.interval).unref()
}

stop() {
Expand Down
13 changes: 5 additions & 8 deletions packages/vitest/src/node/reporters/summary.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Vitest } from '../core'
import type { TestSpecification } from '../spec'
import type { Reporter } from '../types/reporter'
import type { ReportedHookContext, TestCase, TestModule } from './reported-tasks'
import c from 'tinyrainbow'
Expand Down Expand Up @@ -75,29 +76,25 @@ export class SummaryReporter implements Reporter {
getWindow: () => this.createSummary(),
})

this.startTimers()

this.ctx.onClose(() => {
clearInterval(this.durationInterval)
this.renderer.stop()
})
}

onPathsCollected(paths?: string[]) {
this.modules.total = (paths || []).length
}

onWatcherRerun() {
onTestRunStart(specifications: ReadonlyArray<TestSpecification>) {
this.runningModules.clear()
this.finishedModules.clear()
this.modules = emptyCounters()
this.tests = emptyCounters()

this.startTimers()
this.renderer.start()

this.modules.total = specifications.length
}

onFinished() {
onTestRunEnd() {
this.runningModules.clear()
this.finishedModules.clear()
this.renderer.finish()
Expand Down
5 changes: 5 additions & 0 deletions packages/vitest/src/node/test-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export class TestRun {
constructor(private vitest: Vitest) {}

async start(specifications: TestSpecification[]) {
const filepaths = specifications.map(spec => spec.moduleId)
this.vitest.state.collectPaths(filepaths)

await this.vitest.report('onPathsCollected', Array.from(new Set(filepaths)))
await this.vitest.report('onSpecsCollected', specifications.map(spec => spec.toJSON()))
await this.vitest.report('onTestRunStart', [...specifications])
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default defineConfig({
test: {
include: ['browser-basic.test.ts'],
browser: {
name: 'chromium',
instances: [{ browser: 'chromium' }],
enabled: true,
headless: true,
provider: 'playwright',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default defineConfig({
test: {
include: ['./browser-custom.test.ts'],
browser: {
name: 'chromium',
instances: [{ browser: 'chromium' }],
enabled: true,
headless: true,
provider: 'playwright',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default defineConfig({
test: {
include: ['./browser-custom.test.ts'],
browser: {
name: 'chromium',
instances: [{ browser: 'chromium' }],
enabled: true,
headless: true,
provider: 'playwright',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default defineConfig({
test: {
include: ['./browser-basic.test.ts'],
browser: {
name: 'chromium',
instances: [{ browser: 'chromium' }],
enabled: true,
headless: true,
provider: 'playwright',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
browser: {
name: 'chromium',
instances: [{ browser: 'chromium' }],
enabled: true,
headless: true,
provider: 'playwright',
Expand Down
1 change: 1 addition & 0 deletions test/core/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export default defineConfig({
setupFiles: [
'./test/setup.ts',
],
reporters: [['default', { summary: true }], 'hanging-process'],
testNamePattern: '^((?!does not include test that).)*$',
coverage: {
provider: 'istanbul',
Expand Down
87 changes: 87 additions & 0 deletions test/reporters/tests/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,93 @@ describe('json reporter', async () => {
expect(result).toMatchSnapshot()
}, 40000)

it('generates empty json with success: false', async () => {
const { stdout } = await runVitest({
reporters: 'json',
root,
includeTaskLocation: true,
}, ['json-non-existing-files'])

const json = JSON.parse(stdout)
json.startTime = 0
expect(json).toMatchInlineSnapshot(`
{
"numFailedTestSuites": 0,
"numFailedTests": 0,
"numPassedTestSuites": 0,
"numPassedTests": 0,
"numPendingTestSuites": 0,
"numPendingTests": 0,
"numTodoTests": 0,
"numTotalTestSuites": 0,
"numTotalTests": 0,
"snapshot": {
"added": 0,
"didUpdate": false,
"failure": false,
"filesAdded": 0,
"filesRemoved": 0,
"filesRemovedList": [],
"filesUnmatched": 0,
"filesUpdated": 0,
"matched": 0,
"total": 0,
"unchecked": 0,
"uncheckedKeysByFile": [],
"unmatched": 0,
"updated": 0,
},
"startTime": 0,
"success": false,
"testResults": [],
}
`)
})

it('generates empty json with success: true', async () => {
const { stdout } = await runVitest({
reporters: 'json',
root,
includeTaskLocation: true,
passWithNoTests: true,
}, ['json-non-existing-files'])

const json = JSON.parse(stdout)
json.startTime = 0
expect(json).toMatchInlineSnapshot(`
{
"numFailedTestSuites": 0,
"numFailedTests": 0,
"numPassedTestSuites": 0,
"numPassedTests": 0,
"numPendingTestSuites": 0,
"numPendingTests": 0,
"numTodoTests": 0,
"numTotalTestSuites": 0,
"numTotalTests": 0,
"snapshot": {
"added": 0,
"didUpdate": false,
"failure": false,
"filesAdded": 0,
"filesRemoved": 0,
"filesRemovedList": [],
"filesUnmatched": 0,
"filesUpdated": 0,
"matched": 0,
"total": 0,
"unchecked": 0,
"uncheckedKeysByFile": [],
"unmatched": 0,
"updated": 0,
},
"startTime": 0,
"success": true,
"testResults": [],
}
`)
})

it.each([
['passed', 'all-passing-or-skipped'],
['passed', 'all-skipped'],
Expand Down
Loading
Loading