From 47dde76f310faf83c35351b9f612d2dc7ca969c0 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 11 Oct 2024 23:06:32 +0900 Subject: [PATCH] fix(vitest): show rollup error details as test error (#6686) --- packages/vitest/src/node/error.ts | 10 +++++++ packages/vitest/src/node/pools/rpc.ts | 26 ++++++++++++++++--- .../rollup-error/not-found-export.test.ts | 1 + .../rollup-error/not-found-package.test.ts | 1 + .../fixtures/rollup-error/vitest.config.ts | 6 +++++ test/config/test/rollup-error.test.ts | 24 +++++++++++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 test/config/fixtures/rollup-error/not-found-export.test.ts create mode 100644 test/config/fixtures/rollup-error/not-found-package.test.ts create mode 100644 test/config/fixtures/rollup-error/vitest.config.ts create mode 100644 test/config/test/rollup-error.test.ts diff --git a/packages/vitest/src/node/error.ts b/packages/vitest/src/node/error.ts index 09f1e48f4082..80e978e5555e 100644 --- a/packages/vitest/src/node/error.ts +++ b/packages/vitest/src/node/error.ts @@ -119,6 +119,16 @@ export function printError( logger.error(`${e.codeFrame}\n`) } + if ('__vitest_rollup_error__' in e) { + // https://github.com/vitejs/vite/blob/95020ab49e12d143262859e095025cf02423c1d9/packages/vite/src/node/server/middlewares/error.ts#L25-L36 + const err = e.__vitest_rollup_error__ as any + logger.error([ + err.plugin && ` Plugin: ${c.magenta(err.plugin)}`, + err.id && ` File: ${c.cyan(err.id)}${err.loc ? `:${err.loc.line}:${err.loc.column}` : ''}`, + err.frame && c.yellow((err.frame as string).split(/\r?\n/g).map(l => ` `.repeat(2) + l).join(`\n`)), + ].filter(Boolean).join('\n')) + } + // E.g. AssertionError from assert does not set showDiff but has both actual and expected properties if (e.diff) { displayDiff(e.diff, logger.console) diff --git a/packages/vitest/src/node/pools/rpc.ts b/packages/vitest/src/node/pools/rpc.ts index e382a1ca45f7..9bfde0e6cb9c 100644 --- a/packages/vitest/src/node/pools/rpc.ts +++ b/packages/vitest/src/node/pools/rpc.ts @@ -33,7 +33,7 @@ export function createMethodsRPC(project: WorkspaceProject, options: MethodsOpti return r?.map as RawSourceMap | undefined }, async fetch(id, transformMode) { - const result = await project.vitenode.fetchResult(id, transformMode) + const result = await project.vitenode.fetchResult(id, transformMode).catch(handleRollupError) const code = result.code if (!cacheFs || result.externalize) { return result @@ -66,10 +66,10 @@ export function createMethodsRPC(project: WorkspaceProject, options: MethodsOpti return { id: tmp } }, resolveId(id, importer, transformMode) { - return project.vitenode.resolveId(id, importer, transformMode) + return project.vitenode.resolveId(id, importer, transformMode).catch(handleRollupError) }, transform(id, environment) { - return project.vitenode.transformModule(id, environment) + return project.vitenode.transformModule(id, environment).catch(handleRollupError) }, onPathsCollected(paths) { ctx.state.collectPaths(paths) @@ -104,3 +104,23 @@ export function createMethodsRPC(project: WorkspaceProject, options: MethodsOpti }, } } + +// serialize rollup error on server to preserve details as a test error +function handleRollupError(e: unknown): never { + if (e instanceof Error && 'plugin' in e) { + // eslint-disable-next-line no-throw-literal + throw { + name: e.name, + message: e.message, + stack: e.stack, + cause: e.cause, + __vitest_rollup_error__: { + plugin: (e as any).plugin, + id: (e as any).id, + loc: (e as any).loc, + frame: (e as any).frame, + }, + } + } + throw e +} diff --git a/test/config/fixtures/rollup-error/not-found-export.test.ts b/test/config/fixtures/rollup-error/not-found-export.test.ts new file mode 100644 index 000000000000..600a254fab5d --- /dev/null +++ b/test/config/fixtures/rollup-error/not-found-export.test.ts @@ -0,0 +1 @@ +import "vite/no-such-export" diff --git a/test/config/fixtures/rollup-error/not-found-package.test.ts b/test/config/fixtures/rollup-error/not-found-package.test.ts new file mode 100644 index 000000000000..176bce25ddc3 --- /dev/null +++ b/test/config/fixtures/rollup-error/not-found-package.test.ts @@ -0,0 +1 @@ +import '@vitejs/no-such-package' diff --git a/test/config/fixtures/rollup-error/vitest.config.ts b/test/config/fixtures/rollup-error/vitest.config.ts new file mode 100644 index 000000000000..9a6d98b5a28c --- /dev/null +++ b/test/config/fixtures/rollup-error/vitest.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vitest/config"; + +// pnpm -C test/config test -- --root fixtures/rollup-error --environment happy-dom +// pnpm -C test/config test -- --root fixtures/rollup-error --environment node + +export default defineConfig({}) diff --git a/test/config/test/rollup-error.test.ts b/test/config/test/rollup-error.test.ts new file mode 100644 index 000000000000..94c7ec3dd619 --- /dev/null +++ b/test/config/test/rollup-error.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from 'vitest' +import { runVitest } from '../../test-utils' + +test('rollup error node', async () => { + const { stdout } = await runVitest({ + root: './fixtures/rollup-error', + environment: 'node', + reporters: ['junit'], + }) + expect(stdout).toContain(`Error: Missing "./no-such-export" specifier in "vite" package`) + expect(stdout).toContain(`Plugin: vite:import-analysis`) + expect(stdout).toContain(`Error: Failed to load url @vitejs/no-such-package`) +}) + +test('rollup error web', async () => { + const { stdout } = await runVitest({ + root: './fixtures/rollup-error', + environment: 'jsdom', + reporters: ['junit'], + }) + expect(stdout).toContain(`Error: Missing "./no-such-export" specifier in "vite" package`) + expect(stdout).toContain(`Plugin: vite:import-analysis`) + expect(stdout).toContain(`Error: Failed to resolve import "@vitejs/no-such-package" from "fixtures/rollup-error/not-found-package.test.ts". Does the file exist?`) +})