Skip to content

Commit

Permalink
fix(reporter): correct error source position in json report (#1909)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
azaleta and antfu committed Aug 29, 2022
1 parent 8aeeb3b commit 44b7fce
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 8 deletions.
11 changes: 6 additions & 5 deletions packages/vitest/src/node/reporters/json.ts
Expand Up @@ -4,7 +4,7 @@ import type { Vitest } from '../../node'
import type { File, Reporter, Suite, TaskState, Test } from '../../types'
import { getSuites, getTests } from '../../utils'
import { getOutputFile } from '../../utils/config-helpers'
import { parseStacktrace } from '../../utils/source-map'
import { interpretSourcePos, parseStacktrace } from '../../utils/source-map'

// for compatibility reasons, the reporter produces a JSON similar to the one produced by the Jest JSON reporter
// the following types are extracted from the Jest repository (and simplified)
Expand Down Expand Up @@ -94,7 +94,7 @@ export class JsonReporter implements Reporter {
startTime = this.start

const endTime = tests.reduce((prev, next) => Math.max(prev, (next.result?.startTime ?? 0) + (next.result?.duration ?? 0)), startTime)
const assertionResults = tests.map((t) => {
const assertionResults = await Promise.all(tests.map(async (t) => {
const ancestorTitles = [] as string[]
let iter: Suite | undefined = t.suite
while (iter) {
Expand All @@ -110,9 +110,9 @@ export class JsonReporter implements Reporter {
title: t.name,
duration: t.result?.duration,
failureMessages: t.result?.error?.message == null ? [] : [t.result.error.message],
location: this.getFailureLocation(t),
location: await this.getFailureLocation(t),
} as FormattedAssertionResult
})
}))

if (tests.some(t => t.result?.state === 'run')) {
this.ctx.logger.warn('WARNING: Some tests are still running when generating the JSON report.'
Expand Down Expand Up @@ -180,12 +180,13 @@ export class JsonReporter implements Reporter {
}
}

protected getFailureLocation(test: Test): Callsite | undefined {
protected async getFailureLocation(test: Test): Promise<Callsite | undefined> {
const error = test.result?.error
if (!error)
return

const stack = parseStacktrace(error)
await interpretSourcePos(stack, this.ctx)
const frame = stack[stack.length - 1]
if (!frame)
return
Expand Down
5 changes: 2 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions test/reporters/fixtures/json-fail.test.ts
@@ -0,0 +1,7 @@
import { expect, test } from 'vitest'

// I am comment1
// I am comment2
test('should fail', () => {
expect(2).toEqual(1)
})
4 changes: 4 additions & 0 deletions test/reporters/fixtures/vitest.config.ts
@@ -0,0 +1,4 @@
import { defineConfig } from 'vitest/config'

export default defineConfig({
})
10 changes: 10 additions & 0 deletions test/reporters/src/context.ts
@@ -1,3 +1,4 @@
import type { ModuleGraph, ViteDevServer } from 'vite'
import type { Logger } from '../../../packages/vitest/src/node/logger'
import type { Vitest } from '../../../packages/vitest/src/node'
import type { StateManager } from '../../../packages/vitest/src/node/state'
Expand All @@ -15,13 +16,22 @@ export function getContext(): Context {
root: '/',
}

const moduleGraph: Partial<ModuleGraph> = {
getModuleById: () => undefined,
}

const server: Partial<ViteDevServer> = {
moduleGraph: moduleGraph as ModuleGraph,
}

const state: Partial<StateManager> = {
filesMap: new Map<string, File>(),
}

const context: Partial<Vitest> = {
state: state as StateManager,
config: config as ResolvedConfig,
server: server as ViteDevServer,
}

context.logger = {
Expand Down
19 changes: 19 additions & 0 deletions test/reporters/tests/__snapshots__/json.test.ts.snap
@@ -0,0 +1,19 @@
// Vitest Snapshot v1

exports[`json reporter > generates correct report 1`] = `
{
"ancestorTitles": [
"",
],
"failureMessages": [
"expected 2 to deeply equal 1",
],
"fullName": " should fail",
"location": {
"column": 12,
"line": 6,
},
"status": "failed",
"title": "should fail",
}
`;
30 changes: 30 additions & 0 deletions test/reporters/tests/json.test.ts
@@ -0,0 +1,30 @@
import { resolve } from 'pathe'
import { execa } from 'execa'
import { describe, expect, it } from 'vitest'

describe('json reporter', async () => {
const root = resolve(__dirname, '../fixtures')

const skip = (process.platform === 'win32' || process.platform === 'darwin') && process.env.CI

it.skipIf(skip)('generates correct report', async () => {
const { stdout } = await execa('npx', ['vitest', 'run', 'json-fail', '--reporter=json'], {
cwd: root,
env: {
...process.env,
CI: 'true',
NO_COLOR: 'true',
},
stdio: 'pipe',
}).catch(e => e)

const data = JSON.parse(stdout)

expect(data.testResults).toHaveLength(1)
expect(data.testResults[0].assertionResults).toHaveLength(1)

const result = data.testResults[0].assertionResults[0]
delete result.duration
expect(result).toMatchSnapshot()
}, 40000)
})
8 changes: 8 additions & 0 deletions test/reporters/vitest.config.ts
@@ -0,0 +1,8 @@
import { defineConfig } from 'vitest/config'

export default defineConfig({
test: {
exclude: ['node_modules', 'fixtures', 'dist'],
testTimeout: 100000,
},
})

0 comments on commit 44b7fce

Please sign in to comment.