-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: improve test summary, skip only/skip tests
- Loading branch information
1 parent
7d1f3ec
commit 689361d
Showing
10 changed files
with
252 additions
and
198 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import { relative } from 'pathe' | ||
import { parse as parseAst } from 'acorn' | ||
import { ancestor as walkAst } from 'acorn-walk' | ||
import type { RawSourceMap } from 'vite-node' | ||
|
||
import type { File, Suite, Vitest } from '../types' | ||
import { TYPECHECK_SUITE } from './constants' | ||
|
||
interface ParsedFile extends File { | ||
start: number | ||
end: number | ||
} | ||
|
||
interface ParsedSuite extends Suite { | ||
start: number | ||
end: number | ||
} | ||
|
||
interface LocalCallDefinition { | ||
start: number | ||
end: number | ||
name: string | ||
type: string | ||
mode: 'run' | 'skip' | 'only' | 'todo' | ||
task: ParsedSuite | ParsedFile | ||
} | ||
|
||
export interface FileInformation { | ||
file: ParsedFile | ||
filepath: string | ||
parsed: string | ||
map: RawSourceMap | null | ||
definitions: LocalCallDefinition[] | ||
} | ||
|
||
export async function collectTests(ctx: Vitest, filepath: string): Promise<null | FileInformation> { | ||
const request = await ctx.vitenode.transformRequest(filepath) | ||
if (!request) | ||
return null | ||
const ast = parseAst(request.code, { | ||
ecmaVersion: 'latest', | ||
allowAwaitOutsideFunction: true, | ||
}) | ||
const file: ParsedFile = { | ||
filepath, | ||
type: 'suite', | ||
id: '-1', | ||
name: relative(ctx.config.root, filepath), | ||
mode: 'run', | ||
tasks: [], | ||
start: ast.start, | ||
end: ast.end, | ||
result: { | ||
state: 'pass', | ||
}, | ||
} | ||
const definitions: LocalCallDefinition[] = [] | ||
const getName = (callee: any): string | null => { | ||
if (!callee) | ||
return null | ||
if (callee.type === 'Identifier') | ||
return callee.name | ||
if (callee.type === 'MemberExpression') { | ||
// direct call as `__vite_ssr__.test()` | ||
if (callee.object?.name?.startsWith('__vite_ssr_')) | ||
return getName(callee.property) | ||
return getName(callee.object?.property) | ||
} | ||
return null | ||
} | ||
walkAst(ast, { | ||
CallExpression(node) { | ||
const { callee } = node as any | ||
const name = getName(callee) | ||
if (!name) | ||
return | ||
if (!['it', 'test', 'describe', 'suite'].includes(name)) | ||
return | ||
const { arguments: [{ value: message }] } = node as any | ||
const property = callee?.property?.name | ||
const mode = !property || property === name ? 'run' : property | ||
if (mode === 'each') | ||
throw new Error(`${name}.each syntax is not supported when testing types`) | ||
definitions.push({ | ||
start: node.start, | ||
end: node.end, | ||
name: message, | ||
type: name, | ||
mode, | ||
} as LocalCallDefinition) | ||
}, | ||
}) | ||
let lastSuite: ParsedSuite = file | ||
const getLatestSuite = (index: number) => { | ||
const suite = lastSuite | ||
while (lastSuite !== file && lastSuite.end < index) | ||
lastSuite = suite.suite as ParsedSuite | ||
return lastSuite | ||
} | ||
definitions.sort((a, b) => a.start - b.start).forEach((definition, idx) => { | ||
const latestSuite = getLatestSuite(definition.start) | ||
let mode = definition.mode | ||
if (latestSuite.mode !== 'run') // inherit suite mode, if it's set | ||
mode = latestSuite.mode | ||
const state = mode === 'run' ? 'pass' : mode | ||
// expectTypeOf and any type error is actually a "test" ("typecheck"), | ||
// and all "test"s should be inside a "suite" | ||
const task: ParsedSuite = { | ||
type: 'suite', | ||
id: idx.toString(), | ||
suite: latestSuite, | ||
file, | ||
tasks: [], | ||
mode, | ||
name: definition.name, | ||
end: definition.end, | ||
start: definition.start, | ||
result: { | ||
state, | ||
}, | ||
} | ||
definition.task = task | ||
latestSuite.tasks.push(task) | ||
if (definition.type === 'describe' || definition.type === 'suite') | ||
lastSuite = task | ||
else | ||
// to show correct amount of "tests" in summary, we mark this with a special symbol | ||
Object.defineProperty(task, TYPECHECK_SUITE, { value: true }) | ||
}) | ||
const markSkippedTests = (suite: Suite) => { | ||
const hasOnly = suite.tasks.some(task => task.mode === 'only') | ||
suite.tasks.forEach((task) => { | ||
if ((hasOnly && task.mode !== 'only') || suite.mode === 'skip') { | ||
task.mode = 'skip' | ||
task.result = { | ||
state: 'skip', | ||
} | ||
} | ||
if (task.type === 'suite') | ||
markSkippedTests(task) | ||
}) | ||
} | ||
markSkippedTests(file) | ||
return { | ||
file, | ||
parsed: request.code, | ||
filepath, | ||
map: request.map as RawSourceMap | null, | ||
definitions, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
export const EXPECT_TYPEOF_MATCHERS = Symbol('vitest:expect-typeof-matchers') | ||
export const TYPECHECK_ERROR = Symbol('vitest:typecheck-error') | ||
export const TYPECHECK_SUITE = Symbol('vitest:typecheck-suite') |
Oops, something went wrong.