Skip to content

Commit

Permalink
Merge branch 'main' into feat-resolveSnapshotPath-context
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa authored Oct 30, 2024
2 parents 5aadc11 + e934f8d commit 63ea057
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 29 deletions.
4 changes: 4 additions & 0 deletions docs/advanced/reporters.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ declare class TestProject {
* @experimental The public Vitest API is experimental and does not follow semver.
*/
readonly workspaceProject: WorkspaceProject
/**
* Vite's dev server instance. Every workspace project has its own server.
*/
readonly vite: ViteDevServer
/**
* Resolved project configuration.
*/
Expand Down
2 changes: 1 addition & 1 deletion docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ Silent console output from tests
Path to setup files. They will be run before each test file.

:::info
Changing setup files will trigger rerun of all tests.
Editing a setup file will automatically trigger a rerun of all tests.
:::

You can use `process.env.VITEST_POOL_ID` (integer-like string) inside to distinguish between threads.
Expand Down
11 changes: 10 additions & 1 deletion packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ export class Vitest {
process.exitCode = 1
}

this.checkUnhandledErrors(errors)
await this.report('onFinished', files, errors)
await this.initCoverageProvider()
await this.coverageProvider?.mergeReports?.(coverages)
Expand Down Expand Up @@ -613,9 +614,11 @@ export class Vitest {
.finally(async () => {
// can be duplicate files if different projects are using the same file
const files = Array.from(new Set(specs.map(spec => spec.moduleId)))
const errors = this.state.getUnhandledErrors()
const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun })

await this.report('onFinished', this.state.getFiles(files), this.state.getUnhandledErrors(), coverage)
this.checkUnhandledErrors(errors)
await this.report('onFinished', this.state.getFiles(files), errors, coverage)
await this.reportCoverage(coverage, allTestsRun)

this.runningPromise = undefined
Expand Down Expand Up @@ -896,6 +899,12 @@ export class Vitest {
}
}

checkUnhandledErrors(errors: unknown[]) {
if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) {
process.exitCode = 1
}
}

private unregisterWatcher = noop
private registerWatcher() {
const watcher = this.server.watcher
Expand Down
21 changes: 21 additions & 0 deletions packages/vitest/src/node/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class Logger {
this.console = new Console({ stdout: outputStream, stderr: errorStream })
this.logUpdate = createLogUpdate(this.outputStream)
this._highlights.clear()
this.registerUnhandledRejection()
}

log(...args: any[]) {
Expand Down Expand Up @@ -317,4 +318,24 @@ export class Logger {
})
this.log(c.red(divider()))
}

private registerUnhandledRejection() {
const onUnhandledRejection = (err: unknown) => {
process.exitCode = 1

this.printError(err, {
fullStack: true,
type: 'Unhandled Rejection',
})

this.error('\n\n')
process.exit()
}

process.on('unhandledRejection', onUnhandledRejection)

this.ctx.onClose(() => {
process.off('unhandledRejection', onUnhandledRejection)
})
}
}
5 changes: 4 additions & 1 deletion packages/vitest/src/node/pools/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ export function createMethodsRPC(project: WorkspaceProject, options: MethodsOpti
ctx.state.catchError(err, type)
},
onFinished(files) {
return ctx.report('onFinished', files, ctx.state.getUnhandledErrors())
const errors = ctx.state.getUnhandledErrors()
ctx.checkUnhandledErrors(errors)

return ctx.report('onFinished', files, errors)
},
onCancel(reason) {
ctx.cancelCurrentRun(reason)
Expand Down
6 changes: 6 additions & 0 deletions packages/vitest/src/node/reported-workspace-project.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ViteDevServer } from 'vite'
import type { ProvidedContext } from '../types/general'
import type { Vitest } from './core'
import type { ResolvedConfig, ResolvedProjectConfig, SerializedConfig } from './types/config'
Expand All @@ -15,6 +16,10 @@ export class TestProject {
*/
public readonly workspaceProject: WorkspaceProject

/**
* Vite's dev server instance. Every workspace project has its own server.
*/
public readonly vite: ViteDevServer
/**
* Resolved project configuration.
*/
Expand All @@ -32,6 +37,7 @@ export class TestProject {
constructor(workspaceProject: WorkspaceProject) {
this.workspaceProject = workspaceProject
this.vitest = workspaceProject.ctx
this.vite = workspaceProject.server
this.globalConfig = workspaceProject.ctx.config
this.config = workspaceProject.config
this.name = workspaceProject.getName()
Expand Down
26 changes: 0 additions & 26 deletions packages/vitest/src/node/reporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,9 @@ export abstract class BaseReporter implements Reporter {
private _lastRunTimer: NodeJS.Timeout | undefined
private _lastRunCount = 0
private _timeStart = new Date()
private _offUnhandledRejection?: () => void

constructor(options: BaseOptions = {}) {
this.isTTY = options.isTTY ?? ((isNode || isDeno) && process.stdout?.isTTY && !isCI)
this.registerUnhandledRejection()
}

get mode() {
Expand All @@ -72,9 +70,6 @@ export abstract class BaseReporter implements Reporter {

onInit(ctx: Vitest) {
this.ctx = ctx
ctx.onClose(() => {
this._offUnhandledRejection?.()
})
ctx.logger.printBanner()
this.start = performance.now()
}
Expand All @@ -90,11 +85,6 @@ export abstract class BaseReporter implements Reporter {
this.end = performance.now()

this.reportSummary(files, errors)
if (errors.length) {
if (!this.ctx.config.dangerouslyIgnoreUnhandledErrors) {
process.exitCode = 1
}
}
}

onTaskUpdate(packs: TaskResultPack[]) {
Expand Down Expand Up @@ -631,22 +621,6 @@ export abstract class BaseReporter implements Reporter {
errorDivider()
}
}

registerUnhandledRejection() {
const onUnhandledRejection = async (err: unknown) => {
process.exitCode = 1
this.ctx.logger.printError(err, {
fullStack: true,
type: 'Unhandled Rejection',
})
this.ctx.logger.error('\n\n')
process.exit()
}
process.on('unhandledRejection', onUnhandledRejection)
this._offUnhandledRejection = () => {
process.off('unhandledRejection', onUnhandledRejection)
}
}
}

function padTitle(str: string) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { test } from "vitest"

test("Some test", () => {
//
})

new Promise((_, reject) => reject(new Error("intentional unhandled error")))
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function setup() {
void new Promise((_, reject) => reject(new Error('intentional unhandled rejection')))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { test } from "vitest"

test("Some test", () => {})

35 changes: 35 additions & 0 deletions test/config/test/dangerously-ignore-unhandled-errors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { expect, test } from 'vitest'

import { runVitest } from '../../test-utils'

test('{ dangerouslyIgnoreUnhandledErrors: true }', async () => {
const { stderr, stdout, exitCode } = await runVitest({
root: 'fixtures/dangerously-ignore-unhandled-errors',
dangerouslyIgnoreUnhandledErrors: true,
})

expect(exitCode).toBe(0)
expect(stdout).toMatch('Vitest caught 1 unhandled error during the test run')
expect(stderr).toMatch('Error: intentional unhandled error')
})

test('{ dangerouslyIgnoreUnhandledErrors: true } without reporter', async () => {
const { exitCode } = await runVitest({
root: 'fixtures/dangerously-ignore-unhandled-errors',
dangerouslyIgnoreUnhandledErrors: true,
reporters: [{ onInit: () => {} }],
})

expect(exitCode).toBe(0)
})

test('{ dangerouslyIgnoreUnhandledErrors: false }', async () => {
const { stderr, stdout, exitCode } = await runVitest({
root: 'fixtures/dangerously-ignore-unhandled-errors',
dangerouslyIgnoreUnhandledErrors: false,
})

expect(exitCode).toBe(1)
expect(stdout).toMatch('Vitest caught 1 unhandled error during the test run')
expect(stderr).toMatch('Error: intentional unhandled error')
})
16 changes: 16 additions & 0 deletions test/config/test/unhandled-rejections.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { expect, test } from 'vitest'

import { runVitest } from '../../test-utils'

test('unhandled rejections of main thread are reported even when no reporter is used', async () => {
const { stderr, exitCode } = await runVitest({
root: 'fixtures/unhandled-rejections',
globalSetup: ['setup-unhandled-rejections.ts'],
reporters: [{ onInit: () => {} }],
})

expect(exitCode).toBe(1)
expect(stderr).toContain('Unhandled Rejection')
expect(stderr).toContain('Error: intentional unhandled rejection')
expect(stderr).toContain('setup-unhandled-rejections.ts:2:42')
})

0 comments on commit 63ea057

Please sign in to comment.