From d1919a069cc0cb6788d90c45d1fab88e777ad75c Mon Sep 17 00:00:00 2001 From: Abdellah Alaoui Solaimani Date: Fri, 7 Oct 2022 11:13:39 +0300 Subject: [PATCH] fix: use correct source maps in stacktrace (#2027) * [vitest] use correct source maps in stacktrace use vitenode server to get a fetch result instead of a transform result. And then get the sourcemap from it. * [vitest] refactor * add tests for stack traces and sourcemaps * commit lockfile * fix linter * fix types linter * remove dynamic content from snapshot * push the correct snapshot * fix tests :) * increase timeout for runner tests * decrease timeout .. not the culprit in CI * move continue below map assignment * guard against accessing vitenode server * reduce the size of snapshots * rename timeout to prevent running more than one --- packages/vitest/src/utils/source-map.ts | 8 +++-- pnpm-lock.yaml | 8 +++++ .../{timeout.test.ts => test-timeout.test.ts} | 0 .../test/__snapshots__/runner.test.ts.snap | 2 +- .../fixtures/add-in-imba.test.imba | 9 +++++ test/stacktraces/fixtures/add-in-js.test.js | 9 +++++ test/stacktraces/fixtures/add.test.ts | 15 ++++++++ test/stacktraces/fixtures/utils.ts | 3 ++ test/stacktraces/fixtures/vite.config.ts | 32 +++++++++++++++++ test/stacktraces/package.json | 13 +++++++ .../test/__snapshots__/runner.test.ts.snap | 34 ++++++++++++++++++ test/stacktraces/test/runner.test.ts | 36 +++++++++++++++++++ test/stacktraces/vite.config.ts | 7 ++++ 13 files changed, 172 insertions(+), 4 deletions(-) rename test/fails/fixtures/{timeout.test.ts => test-timeout.test.ts} (100%) create mode 100644 test/stacktraces/fixtures/add-in-imba.test.imba create mode 100644 test/stacktraces/fixtures/add-in-js.test.js create mode 100644 test/stacktraces/fixtures/add.test.ts create mode 100644 test/stacktraces/fixtures/utils.ts create mode 100644 test/stacktraces/fixtures/vite.config.ts create mode 100644 test/stacktraces/package.json create mode 100644 test/stacktraces/test/__snapshots__/runner.test.ts.snap create mode 100644 test/stacktraces/test/runner.test.ts create mode 100644 test/stacktraces/vite.config.ts diff --git a/packages/vitest/src/utils/source-map.ts b/packages/vitest/src/utils/source-map.ts index e4b734790eae..b5ed47277d8e 100644 --- a/packages/vitest/src/utils/source-map.ts +++ b/packages/vitest/src/utils/source-map.ts @@ -25,10 +25,12 @@ export async function interpretSourcePos(stackFrames: ParsedStack[], ctx: Vitest for (const frame of stackFrames) { if ('sourcePos' in frame) continue - const transformResult = ctx.server.moduleGraph.getModuleById(frame.file)?.ssrTransformResult - if (!transformResult) + const ssrTransformResult = ctx.server.moduleGraph.getModuleById(frame.file)?.ssrTransformResult + const fetchResult = ctx.vitenode?.fetchCache.get(frame.file)?.result + const map = fetchResult?.map || ssrTransformResult?.map + if (!map) continue - const sourcePos = await getOriginalPos(transformResult.map as any as RawSourceMap | undefined, frame) + const sourcePos = await getOriginalPos(map as any as RawSourceMap, frame) if (sourcePos) frame.sourcePos = sourcePos } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f1b4b5f646d..dcdf89529f69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1070,6 +1070,14 @@ importers: dependencies: vitest: link:../../packages/vitest + test/stacktraces: + specifiers: + execa: ^6.1.0 + vitest: workspace:* + devDependencies: + execa: 6.1.0 + vitest: link:../../packages/vitest + test/vite-config: specifiers: pathe: ^0.2.0 diff --git a/test/fails/fixtures/timeout.test.ts b/test/fails/fixtures/test-timeout.test.ts similarity index 100% rename from test/fails/fixtures/timeout.test.ts rename to test/fails/fixtures/test-timeout.test.ts diff --git a/test/fails/test/__snapshots__/runner.test.ts.snap b/test/fails/test/__snapshots__/runner.test.ts.snap index 46844e79c850..57239f2dd6ec 100644 --- a/test/fails/test/__snapshots__/runner.test.ts.snap +++ b/test/fails/test/__snapshots__/runner.test.ts.snap @@ -14,4 +14,4 @@ exports[`should fails > nested-suite.test.ts > nested-suite.test.ts 1`] = `"Asse exports[`should fails > stall.test.ts > stall.test.ts 1`] = `"TypeError: failure"`; -exports[`should fails > timeout.test.ts > timeout.test.ts 1`] = `"Error: Test timed out in 10ms."`; +exports[`should fails > test-timeout.test.ts > test-timeout.test.ts 1`] = `"Error: Test timed out in 10ms."`; diff --git a/test/stacktraces/fixtures/add-in-imba.test.imba b/test/stacktraces/fixtures/add-in-imba.test.imba new file mode 100644 index 000000000000..ca19b2742100 --- /dev/null +++ b/test/stacktraces/fixtures/add-in-imba.test.imba @@ -0,0 +1,9 @@ +import {it, expect} from 'vitest' + +export def add(...args) + return args.reduce((do(a, b) a + b), 0) + +it "add", do + expect(add()).toBe 0 + expect(add(1)).toBe 3 + expect(add(1, 2, 3)).toBe 6 diff --git a/test/stacktraces/fixtures/add-in-js.test.js b/test/stacktraces/fixtures/add-in-js.test.js new file mode 100644 index 000000000000..d28ddbc4dc0f --- /dev/null +++ b/test/stacktraces/fixtures/add-in-js.test.js @@ -0,0 +1,9 @@ +/* body */ +import { expect, it } from 'vitest' +import { add } from './utils' + +it('add', () => { + expect(add()).toBe(100) + expect(add(1)).toBe(1) + return expect(add(1, 2, 3)).toBe(6) +}) diff --git a/test/stacktraces/fixtures/add.test.ts b/test/stacktraces/fixtures/add.test.ts new file mode 100644 index 000000000000..719dbf5bb83d --- /dev/null +++ b/test/stacktraces/fixtures/add.test.ts @@ -0,0 +1,15 @@ +/* body */ +import { expect, it } from 'vitest' +import { add } from './utils' + +interface Num { + count: number +} + +const a: Num = { count: 10 } + +it('add', () => { + expect(add(a.count)).toBe(100) + expect(add(1)).toBe(1) + return expect(add(1, 2, 3)).toBe(6) +}) diff --git a/test/stacktraces/fixtures/utils.ts b/test/stacktraces/fixtures/utils.ts new file mode 100644 index 000000000000..ad129e7f4213 --- /dev/null +++ b/test/stacktraces/fixtures/utils.ts @@ -0,0 +1,3 @@ +export function add(...args: number[]) { + return args.reduce((a, b) => { return a + b }, 0) +} diff --git a/test/stacktraces/fixtures/vite.config.ts b/test/stacktraces/fixtures/vite.config.ts new file mode 100644 index 000000000000..766ce8757db1 --- /dev/null +++ b/test/stacktraces/fixtures/vite.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [{ + name: 'vite-plugin-imba', + transform(code, id) { + if (id.endsWith('.imba')) { + return { + code: + '\n/*body*/\nimport {it,expect} from \'vitest\';\n\nexport function add(...args){\n\t\n\treturn args.reduce(function(a,b) { return a + b; },0);\n};\n\nit("add",function() {\n\t\n\texpect(add()).toBe(0);\n\texpect(add(1)).toBe(3);\n\treturn expect(add(1,2,3)).toBe(6);\n});\n\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMudGVzdC5pbWJhIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidXRpbHMudGVzdC5pbWJhIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7aXQsIGV4cGVjdH0gZnJvbSAndml0ZXN0J1xuXG5leHBvcnQgZGVmIGFkZCguLi5hcmdzKVxuXHRyZXR1cm4gYXJncy5yZWR1Y2UoKGRvKGEsIGIpIGEgKyBiKSwgMClcblxuaXQgXCJhZGRcIiwgZG9cblx0ZXhwZWN0KGFkZCgpKS50b0JlIDBcblx0ZXhwZWN0KGFkZCgxKSkudG9CZSAzXG5cdGV4cGVjdChhZGQoMSwgMiwgMykpLnRvQmUgNlxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsTUFBTSxFQUFFLEVBQUUsQ0FBRSxNQUFNLE9BQU8sUUFBUTs7QUFFakMsTUFBTSxDQUFDLFFBQUcsQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDOztDQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBRSxRQUFFLENBQUMsQ0FBQyxDQUFFLENBQUMsSUFBRSxPQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFHLENBQUMsQ0FBQztDQUFBOztBQUV4QyxFQUFFLENBQUMsS0FBSyxDQUFFLFFBQUUsR0FBQTs7Q0FDWCxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0NBQ3BCLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0NBQ3JCLE9BQUEsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUUsQ0FBQyxDQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtDQUFBLENBSDFCO0FBSUY7In0=', + map: { + version: 3, + file: 'add-in-imba.test.imba', + names: [], + sourceRoot: '', + sources: ['add-in-imba.test.imba'], + sourcesContent: [ + 'import {it, expect} from \'vitest\'\n\nexport def add(...args)\n\treturn args.reduce((do(a, b) a + b), 0)\n\nit "add", do\n\texpect(add()).toBe 0\n\texpect(add(1)).toBe 3\n\texpect(add(1, 2, 3)).toBe 6\n', + ], + mappings: + ';;AAAA,MAAM,EAAE,EAAE,CAAE,MAAM,OAAO,QAAQ;;AAEjC,MAAM,CAAC,QAAG,CAAC,GAAG,IAAI,IAAI,CAAC;;CACtB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAE,QAAE,CAAC,CAAC,CAAE,CAAC,IAAE,OAAA,CAAC,CAAC,CAAC,CAAC,CAAC,IAAG,CAAC,CAAC;CAAA;;AAExC,EAAE,CAAC,KAAK,CAAE,QAAE,GAAA;;CACX,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;CACpB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;CACrB,OAAA,MAAM,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;CAAA,CAH1B;AAIF;', + }, + } + } + }, + }], + test: { + threads: false, + isolate: false, + include: ['**/*.{test,spec}.{imba,js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + }, +}) diff --git a/test/stacktraces/package.json b/test/stacktraces/package.json new file mode 100644 index 000000000000..818202bc1bc0 --- /dev/null +++ b/test/stacktraces/package.json @@ -0,0 +1,13 @@ +{ + "name": "@vitest/test-fails", + "type": "module", + "private": true, + "scripts": { + "test": "vitest", + "coverage": "vitest run --coverage" + }, + "devDependencies": { + "execa": "^6.1.0", + "vitest": "workspace:*" + } +} diff --git a/test/stacktraces/test/__snapshots__/runner.test.ts.snap b/test/stacktraces/test/__snapshots__/runner.test.ts.snap new file mode 100644 index 000000000000..54b488ab5a80 --- /dev/null +++ b/test/stacktraces/test/__snapshots__/runner.test.ts.snap @@ -0,0 +1,34 @@ +// Vitest Snapshot v1 + +exports[`stacktraces should respect sourcemaps > add.test.ts > add.test.ts 1`] = ` +" ❯ add.test.ts:12:23 + 10| + 11| it('add', () => { + 12| expect(add(a.count)).toBe(100) + | ^ + 13| expect(add(1)).toBe(1) + 14| return expect(add(1, 2, 3)).toBe(6) +" +`; + +exports[`stacktraces should respect sourcemaps > add-in-imba.test.imba > add-in-imba.test.imba 1`] = ` +" ❯ add-in-imba.test.imba:8:16 + 6| it \\"add\\", do + 7| expect(add()).toBe 0 + 8| expect(add(1)).toBe 3 + | ^ + 9| expect(add(1, 2, 3)).toBe 6 + 10| +" +`; + +exports[`stacktraces should respect sourcemaps > add-in-js.test.js > add-in-js.test.js 1`] = ` +" ❯ add-in-js.test.js:6:17 + 4| + 5| it('add', () => { + 6| expect(add()).toBe(100) + | ^ + 7| expect(add(1)).toBe(1) + 8| return expect(add(1, 2, 3)).toBe(6) +" +`; diff --git a/test/stacktraces/test/runner.test.ts b/test/stacktraces/test/runner.test.ts new file mode 100644 index 000000000000..f5110934e39f --- /dev/null +++ b/test/stacktraces/test/runner.test.ts @@ -0,0 +1,36 @@ +import { resolve } from 'pathe' +import fg from 'fast-glob' +import { execa } from 'execa' +import { describe, expect, it } from 'vitest' + +describe('stacktraces should respect sourcemaps', async () => { + const root = resolve(__dirname, '../fixtures') + const files = await fg('*.test.*', { cwd: root }) + + for (const file of files) { + it(file, async () => { + // in Windows child_process is very unstable, we skip testing it + if (process.platform === 'win32' && process.env.CI) + return + + let error: any + await execa('npx', ['vitest', 'run', file], { + cwd: root, + env: { + ...process.env, + CI: 'true', + NO_COLOR: 'true', + }, + }) + .catch((e) => { + error = e + }) + + expect(error).toBeTruthy() + const lines = String(error).split(/\n/g) + const index = lines.findIndex(val => val.includes(`${file}:`)) + const msg = lines.slice(index, index + 8).join('\n') + expect(msg).toMatchSnapshot(file) + }, 10000) + } +}) diff --git a/test/stacktraces/vite.config.ts b/test/stacktraces/vite.config.ts new file mode 100644 index 000000000000..41bc8c0ff39f --- /dev/null +++ b/test/stacktraces/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + test: { + include: ['test/*.test.ts'], + }, +})