From 1ffb0ef5489bcf873e879d61f3bdcebd364430c2 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 11 Jan 2023 17:30:49 +0100 Subject: [PATCH] feat: add more information about unhandler error (#2642) * feat: add more information about unhandler error * chore: fix type issue --- packages/vitest/src/node/error.ts | 17 +++++++++++++---- packages/vitest/src/runtime/worker.ts | 15 +++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/vitest/src/node/error.ts b/packages/vitest/src/node/error.ts index 31c30fa03781..e5f696169434 100644 --- a/packages/vitest/src/node/error.ts +++ b/packages/vitest/src/node/error.ts @@ -66,6 +66,17 @@ export async function printError(error: unknown, ctx: Vitest, options: PrintErro }) } + const testPath = (e as any).VITEST_TEST_PATH + const testName = (e as any).VITEST_TEST_NAME + // testName has testPath inside + if (testPath && !testName) + ctx.logger.error(c.red(`This error originated in "${c.bold(testPath)}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`)) + if (testName) { + ctx.logger.error(c.red(`The latest test that migh've cause the error is "${c.bold(testName)}". It might mean one of the following:` + + '\n- The error was thrown, while Vitest was running this test.' + + '\n- This was the last recorder test before the error was thrown, if error originated after test finished its execution.')) + } + if (typeof e.cause === 'object' && e.cause && 'name' in e.cause) { (e.cause as any).name = `Caused by: ${(e.cause as any).name}` await printError(e.cause, ctx, { fullStack, showCodeFrame: false }) @@ -97,6 +108,8 @@ const skipErrorProperties = new Set([ 'showDiff', 'actual', 'expected', + 'VITEST_TEST_NAME', + 'VITEST_TEST_PATH', ...Object.getOwnPropertyNames(Error.prototype), ...Object.getOwnPropertyNames(Object.prototype), ]) @@ -183,10 +196,6 @@ function printStack( logger.error(color(` ${c.dim(F_POINTER)} ${[frame.method, c.dim(`${path}:${frame.line}:${frame.column}`)].filter(Boolean).join(' ')}`)) onStack?.(frame) - - // reached at test file, skip the follow stack - if (frame.file in ctx.state.filesMap) - break } logger.error() const hasProperties = Object.keys(errorProperties).length > 0 diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index ce9d8326be20..245bcdebe7af 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -1,7 +1,8 @@ -import { resolve } from 'pathe' +import { relative, resolve } from 'pathe' import { createBirpc } from 'birpc' import { workerId as poolId } from 'tinypool' import { ModuleCacheMap } from 'vite-node/client' +import { isPrimitive } from 'vite-node/utils' import type { ResolvedConfig, WorkerContext, WorkerRPC } from '../types' import { distDir } from '../constants' import { getWorkerState } from '../utils' @@ -21,6 +22,8 @@ async function startViteNode(ctx: WorkerContext) { if (_viteNode) return _viteNode + const { config } = ctx + const processExit = process.exit process.exit = (code = process.exitCode || 0): never => { @@ -30,11 +33,15 @@ async function startViteNode(ctx: WorkerContext) { } process.on('unhandledRejection', (err) => { - rpc().onUnhandledRejection(processError(err)) + const worker = getWorkerState() + const error = processError(err) + if (worker.filepath && !isPrimitive(error)) { + error.VITEST_TEST_NAME = worker.current?.name + error.VITEST_TEST_PATH = relative(config.root, worker.filepath) + } + rpc().onUnhandledRejection(error) }) - const { config } = ctx - const { run } = (await executeInViteNode({ files: [ resolve(distDir, 'entry.js'),