diff --git a/eslint.config.js b/eslint.config.js index d4cb718bb..42ccb851b 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -26,6 +26,7 @@ export default antfu( 'test/coverage-test/src/transpiled.js', 'test/coverage-test/src/original.ts', 'test/e2e/deps/error/*', + 'test/e2e/deps/malformed-source-map/*.js', 'examples/**/mockServiceWorker.js', 'examples/sveltekit/.svelte-kit', 'packages/browser/**/esm-client-injector.js', diff --git a/packages/utils/src/source-map/node.ts b/packages/utils/src/source-map/node.ts index cb6a342a3..93bfe1eee 100644 --- a/packages/utils/src/source-map/node.ts +++ b/packages/utils/src/source-map/node.ts @@ -12,14 +12,19 @@ export function extractSourcemapFromFile( code: string, filePath: string, ): ExtractedSourceMap | undefined { - const map = ( - convertSourceMap.fromSource(code) - || convertSourceMap.fromMapFileSource( - code, - createConvertSourceMapReadMap(filePath), - ) - )?.toObject() - return map ? { map } : undefined + try { + const map = ( + convertSourceMap.fromSource(code) + || convertSourceMap.fromMapFileSource( + code, + createConvertSourceMapReadMap(filePath), + ) + )?.toObject() + return map ? { map } : undefined + } + catch { + return undefined + } } function createConvertSourceMapReadMap(originalFileName: string) { diff --git a/packages/vitest/src/node/test-run.ts b/packages/vitest/src/node/test-run.ts index 289befcbe..55364468f 100644 --- a/packages/vitest/src/node/test-run.ts +++ b/packages/vitest/src/node/test-run.ts @@ -189,6 +189,8 @@ export class TestRun { // source map is already applied for inlined modules. // Module node exists due to Vitest fetch module, // but transformResult should be empty for external modules. + // TODO: this uses client module graph and thus miss detects + // inlined modules in ssr environment as if external. const mod = project.vite.moduleGraph.getModuleById(file) if (!mod?.transformResult && existsSync(file)) { const code = readFileSync(file, 'utf-8') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5363d69b..e6de7d520 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1307,6 +1307,9 @@ importers: '@test/test-dep-linked': specifier: link:./deps/linked version: link:deps/linked + '@test/test-dep-malformed-source-map': + specifier: file:./deps/malformed-source-map + version: file:test/e2e/deps/malformed-source-map '@test/test-dep-url': specifier: link:./deps/dep-url version: link:deps/dep-url @@ -4947,6 +4950,9 @@ packages: '@test/test-dep-error@file:test/e2e/deps/error': resolution: {directory: test/e2e/deps/error, type: directory} + '@test/test-dep-malformed-source-map@file:test/e2e/deps/malformed-source-map': + resolution: {directory: test/e2e/deps/malformed-source-map, type: directory} + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -13392,6 +13398,8 @@ snapshots: '@test/test-dep-error@file:test/e2e/deps/error': {} + '@test/test-dep-malformed-source-map@file:test/e2e/deps/malformed-source-map': {} + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.7 diff --git a/test/e2e/deps/malformed-source-map/external-map.js b/test/e2e/deps/malformed-source-map/external-map.js new file mode 100644 index 000000000..3969a55ea --- /dev/null +++ b/test/e2e/deps/malformed-source-map/external-map.js @@ -0,0 +1,5 @@ +export default function testMalformedSourceMap() { + throw new Error('test error') +} + +//# sourceMappingURL=external-map.js.map diff --git a/test/e2e/deps/malformed-source-map/external-map.js.map b/test/e2e/deps/malformed-source-map/external-map.js.map new file mode 100644 index 000000000..0bac59e9d --- /dev/null +++ b/test/e2e/deps/malformed-source-map/external-map.js.map @@ -0,0 +1 @@ +not-json diff --git a/test/e2e/deps/malformed-source-map/index.js b/test/e2e/deps/malformed-source-map/index.js new file mode 100644 index 000000000..f943ce19d --- /dev/null +++ b/test/e2e/deps/malformed-source-map/index.js @@ -0,0 +1,7 @@ +const embeddedSourceMapComment = ` +//# sourceMappingURL=data:application/json;base64,bm90LWpzb24= +` + +export default function testMalformedSourceMap() { + throw new Error('test error') +} diff --git a/test/e2e/deps/malformed-source-map/package.json b/test/e2e/deps/malformed-source-map/package.json new file mode 100644 index 000000000..d01a79111 --- /dev/null +++ b/test/e2e/deps/malformed-source-map/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/test-dep-malformed-source-map", + "type": "module", + "private": true, + "exports": { + ".": "./index.js", + "./external-map": "./external-map.js" + } +} diff --git a/test/e2e/fixtures/malformed-source-map/external-map.spec.ts b/test/e2e/fixtures/malformed-source-map/external-map.spec.ts new file mode 100644 index 000000000..b25a230fb --- /dev/null +++ b/test/e2e/fixtures/malformed-source-map/external-map.spec.ts @@ -0,0 +1,6 @@ +import { test } from 'vitest' +import testMalformedSourceMap from '@test/test-dep-malformed-source-map/external-map' + +test('reports the original module error', () => { + testMalformedSourceMap() +}) diff --git a/test/e2e/fixtures/malformed-source-map/external-module.spec.ts b/test/e2e/fixtures/malformed-source-map/external-module.spec.ts new file mode 100644 index 000000000..5ac770b8c --- /dev/null +++ b/test/e2e/fixtures/malformed-source-map/external-module.spec.ts @@ -0,0 +1,6 @@ +import { test } from 'vitest' +import testMalformedSourceMap from '@test/test-dep-malformed-source-map' + +test('reports the original module error', () => { + testMalformedSourceMap() +}) diff --git a/test/e2e/fixtures/malformed-source-map/inlined-module.spec.ts b/test/e2e/fixtures/malformed-source-map/inlined-module.spec.ts new file mode 100644 index 000000000..d04c9180a --- /dev/null +++ b/test/e2e/fixtures/malformed-source-map/inlined-module.spec.ts @@ -0,0 +1,6 @@ +import { test } from 'vitest' +import testMalformedSourceMap from './malformed-source-map.js' + +test('reports the original module error', () => { + testMalformedSourceMap() +}) diff --git a/test/e2e/fixtures/malformed-source-map/malformed-source-map.js b/test/e2e/fixtures/malformed-source-map/malformed-source-map.js new file mode 100644 index 000000000..f943ce19d --- /dev/null +++ b/test/e2e/fixtures/malformed-source-map/malformed-source-map.js @@ -0,0 +1,7 @@ +const embeddedSourceMapComment = ` +//# sourceMappingURL=data:application/json;base64,bm90LWpzb24= +` + +export default function testMalformedSourceMap() { + throw new Error('test error') +} diff --git a/test/e2e/package.json b/test/e2e/package.json index 9c9d0c587..fa6c3d4e6 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -18,6 +18,7 @@ "@test/test-dep-config": "link:./deps/test-dep-config", "@test/test-dep-error": "file:./deps/error", "@test/test-dep-linked": "link:./deps/linked", + "@test/test-dep-malformed-source-map": "file:./deps/malformed-source-map", "@test/test-dep-url": "link:./deps/dep-url", "@types/ws": "catalog:", "@vitejs/plugin-basic-ssl": "^2.3.0", diff --git a/test/e2e/test/malformed-source-map.test.ts b/test/e2e/test/malformed-source-map.test.ts new file mode 100644 index 000000000..6c22377a2 --- /dev/null +++ b/test/e2e/test/malformed-source-map.test.ts @@ -0,0 +1,28 @@ +import { expect, test } from 'vitest' +import { runVitest } from '#test-utils' + +test('reports errors from modules with malformed source maps (#10892)', async () => { + const { errorTree } = await runVitest({ + root: './fixtures/malformed-source-map', + }, [], { fails: true }) + + expect(errorTree()).toMatchInlineSnapshot(` + { + "external-map.spec.ts": { + "reports the original module error": [ + "test error", + ], + }, + "external-module.spec.ts": { + "reports the original module error": [ + "test error", + ], + }, + "inlined-module.spec.ts": { + "reports the original module error": [ + "test error", + ], + }, + } + `) +})