Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/vitest-dev/vscode. VS Code extension for Vitest vitest.dev/vscode
testing vitest vscode
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200import type { TestError } from 'vitest'import type * as vscode from 'vscode'import type { VitestProcessAPI } from './apiProcess'
export type TestData = TestFolder | TestFile | TestCase | TestSuite
const WEAKMAP_TEST_DATA = new WeakMap<vscode.TestItem, TestData>()
export function getTestData(item: vscode.TestItem): TestData { const data = WEAKMAP_TEST_DATA.get(item) if (!data) throw new Error( `Test data not found for "${item.label}". This is a bug in Vitest extension. Please report it to https://github.com/vitest-dev/vscode`, ) return data}
function addTestData<T extends TestData>(item: vscode.TestItem, data: T): T { WEAKMAP_TEST_DATA.set(item, data) return data}
class BaseTestData { public readonly label: string public readonly parent: TestData | undefined public readonly id: string
constructor(item: vscode.TestItem, parent?: vscode.TestItem) { this.label = item.label this.id = item.id this.parent = parent ? WEAKMAP_TEST_DATA.get(parent) : undefined }}
export class TestFolder extends BaseTestData { public readonly type = 'folder'
private constructor(item: vscode.TestItem, parent?: vscode.TestItem) { super(item, parent) }
public static register(item: vscode.TestItem, parent?: vscode.TestItem) { return addTestData(item, new TestFolder(item, parent)) }}
export interface TestFileMetadata { project: string pool: string browser?: { provider: string name: string webRoot: string }}
export class TestFile extends BaseTestData { public readonly type = 'file' public readonly project: string
private constructor( item: vscode.TestItem, parent: vscode.TestItem, public readonly filepath: string, public readonly api: VitestProcessAPI, public readonly metadata: TestFileMetadata, ) { super(item, parent) this.project = metadata.project }
public static register( item: vscode.TestItem, parent: vscode.TestItem, filepath: string, api: VitestProcessAPI, metadata: TestFileMetadata, ) { return addTestData(item, new TestFile(item, parent, filepath, api, metadata)) }}
class TaskName { constructor( private readonly data: TestCase | TestSuite, public readonly dynamic: boolean, ) {}
public get label() { return this.data.label }
getTestNamePattern() { const patterns = [escapeTestName(this.data.label, this.dynamic)] let iter = this.data.parent while (iter) { // if we reached test file, then stop if (iter instanceof TestFile || iter instanceof TestFolder) break patterns.push(escapeTestName(iter.label, iter.name.dynamic)) iter = iter.parent } if (this.data.file.api.usesJestTestNamePattern) { // vitest's test task name starts with ' ' of root suite // It's considered as a bug, but it's not fixed until Vitest 5 for backward compatibility return `\\s?${patterns.reverse().join(' ')}` } // since 5.0.0-rc.1 the pattern is matched against names joined with " > " return patterns.reverse().join(' > ') }}
export class TestCase extends BaseTestData { public name: TaskName public readonly type = 'test' public errors: TestError[] | undefined
private constructor( item: vscode.TestItem, parent: vscode.TestItem, public readonly file: TestFile, public readonly dynamic: boolean, ) { super(item, parent) this.name = new TaskName(this, dynamic) }
public static register( item: vscode.TestItem, parent: vscode.TestItem, file: TestFile, dynamic: boolean, ) { return addTestData(item, new TestCase(item, parent, file, dynamic)) }
setErrors(errors: TestError[] | undefined) { this.errors = errors }
getTestNamePattern() { return `^${this.name.getTestNamePattern()}$` }}
export class TestSuite extends BaseTestData { public name: TaskName public readonly type = 'suite'
private constructor( item: vscode.TestItem, parent: vscode.TestItem, public readonly file: TestFile, dynamic: boolean, ) { super(item, parent) this.name = new TaskName(this, dynamic) }
public static register( item: vscode.TestItem, parent: vscode.TestItem, file: TestFile, dynamic: boolean, ) { return addTestData(item, new TestSuite(item, parent, file, dynamic)) }
getTestNamePattern() { return `^${this.name.getTestNamePattern()}` }}
function escapeRegex(str: string) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}
const kReplacers = new Map<string, string>([ ['%i', '\\d+?'], ['%#', '\\d+?'], ['%d', '[\\d.eE+-]+?'], ['%f', '[\\d.eE+-]+?'], ['%s', '.+?'], ['%j', '.+?'], ['%o', '.+?'], ['%%', '%'],])
function escapeTestName(label: string, dynamic: boolean) { if (!dynamic) { return escapeRegex(label) }
// Replace object access patterns ($value, $obj.a) with %s first let pattern = label.replace(/\$[a-z_.]+/gi, '%s') pattern = escapeRegex(pattern) // Replace percent placeholders with their respective regex pattern = pattern.replace(/%[i#dfsjo%]/g, (m) => kReplacers.get(m) || m) return pattern}