Skip to content

Commit

Permalink
Use include and exclude options from vite config. (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
huwshimi authored Oct 18, 2023
1 parent 2ae0589 commit d62ca01
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 18 deletions.
20 changes: 15 additions & 5 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as vscode from 'vscode'
import semver from 'semver'
import type { WorkspaceConfiguration, WorkspaceFolder } from 'vscode'
import type { ResolvedConfig } from 'vitest'
import { configDefaults } from 'vitest/config'
import { isDefinitelyVitestEnv, mayBeVitestEnv } from './pure/isVitestEnv'
import { getVitestCommand, getVitestVersion, isNodeAvailable } from './pure/utils'
import { log } from './log'
Expand All @@ -10,8 +12,8 @@ export function getConfigValue<T>(
rootConfig: WorkspaceConfiguration,
folderConfig: WorkspaceConfiguration,
key: string,
defaultValue: T,
): T {
defaultValue?: T,
): T | undefined {
return folderConfig.get(key) ?? rootConfig.get(key) ?? defaultValue
}

Expand All @@ -25,18 +27,26 @@ export function getConfig(workspaceFolder?: WorkspaceFolder | vscode.Uri | strin
const folderConfig = vscode.workspace.getConfiguration('vitest', workspace)
const rootConfig = vscode.workspace.getConfiguration('vitest')

const get = <T>(key: string, defaultValue: T) => getConfigValue<T>(rootConfig, folderConfig, key, defaultValue)
const get = <T>(key: string, defaultValue?: T) => getConfigValue<T>(rootConfig, folderConfig, key, defaultValue)

return {
env: get<null | Record<string, string>>('nodeEnv', null),
commandLine: get<string | undefined>('commandLine', undefined),
include: get<string[]>('include', []),
exclude: get<string[]>('exclude', []),
include: get<string[]>('include'),
exclude: get<string[]>('exclude'),
enable: get<boolean>('enable', false),
debugExclude: get<string[]>('debugExclude', []),
}
}

export function getCombinedConfig(config: ResolvedConfig, workspaceFolder?: WorkspaceFolder | vscode.Uri | string) {
const vitestConfig = getConfig(workspaceFolder)
return {
exclude: vitestConfig.exclude || config.exclude || configDefaults.exclude,
include: vitestConfig.include || config.include || configDefaults.include,
}
}

export function getRootConfig() {
const rootConfig = vscode.workspace.getConfiguration('vitest')

Expand Down
17 changes: 10 additions & 7 deletions src/discover.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path, { sep } from 'path'
import * as vscode from 'vscode'
import minimatch from 'minimatch'
import type { ResolvedConfig } from 'vitest'
import parse from './pure/parsers'
import type { NamedBlock } from './pure/parsers/parser_nodes'
import type { TestData } from './TestData'
Expand All @@ -13,7 +14,7 @@ import {
} from './TestData'
import { shouldIncludeFile } from './vscodeUtils'

import { getConfig, vitestEnvironmentFolders } from './config'
import { getCombinedConfig, vitestEnvironmentFolders } from './config'
import { log } from './log'

export class TestFileDiscoverer extends vscode.Disposable {
Expand All @@ -22,8 +23,9 @@ export class TestFileDiscoverer extends vscode.Disposable {
private workspaceCommonPrefix: Map<string, string> = new Map()
private workspaceItems: Map<string, Set<vscode.TestItem>> = new Map()
private pathToFileItem: Map<string, TestFile> = new Map()
private config: ResolvedConfig

constructor() {
constructor(config: ResolvedConfig) {
super(() => {
for (const watch of this.lastWatches)
watch.dispose()
Expand All @@ -33,6 +35,7 @@ export class TestFileDiscoverer extends vscode.Disposable {
this.pathToFileItem.clear()
this.workspaceCommonPrefix.clear()
})
this.config = config
this.workspacePaths
= vscode.workspace.workspaceFolders?.map(x => x.uri.fsPath) || []
}
Expand All @@ -49,8 +52,8 @@ export class TestFileDiscoverer extends vscode.Disposable {
const watchers = [] as vscode.FileSystemWatcher[]
await Promise.all(
vitestEnvironmentFolders.map(async (workspaceFolder) => {
const exclude = getConfig(workspaceFolder).exclude
for (const include of getConfig(workspaceFolder).include) {
const exclude = getCombinedConfig(this.config, workspaceFolder).exclude
for (const include of getCombinedConfig(this.config, workspaceFolder).include) {
const pattern = new vscode.RelativePattern(
workspaceFolder.uri,
include,
Expand Down Expand Up @@ -103,8 +106,8 @@ export class TestFileDiscoverer extends vscode.Disposable {

await Promise.all(
vscode.workspace.workspaceFolders.map(async (workspaceFolder) => {
const exclude = getConfig(workspaceFolder).exclude
for (const include of getConfig(workspaceFolder).include) {
const exclude = getCombinedConfig(this.config, workspaceFolder).exclude
for (const include of getCombinedConfig(this.config, workspaceFolder).include) {
const pattern = new vscode.RelativePattern(
workspaceFolder.uri,
include,
Expand All @@ -130,7 +133,7 @@ export class TestFileDiscoverer extends vscode.Disposable {
if (e.uri.scheme !== 'file')
return

if (!shouldIncludeFile(e.uri.fsPath))
if (!shouldIncludeFile(e.uri.fsPath, this.config))
return

const { file, data } = this.getOrCreateFile(ctrl, e.uri)
Expand Down
13 changes: 10 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from 'vscode'

import { effect } from '@vue/reactivity'

import type { ResolvedConfig } from 'vitest'
import { Command } from './command'
import {
detectVitestEnvironmentFolders, extensionId, getVitestWorkspaceConfigs,
Expand All @@ -17,6 +18,7 @@ import { TestFile, WEAKMAP_TEST_DATA } from './TestData'
import { TestWatcher } from './watch'

import type { VitestWorkspaceConfig } from './config'
import { fetchVitestConfig } from './pure/watch/vitestConfig'

export async function activate(context: vscode.ExtensionContext) {
await detectVitestEnvironmentFolders()
Expand All @@ -26,7 +28,6 @@ export async function activate(context: vscode.ExtensionContext) {
}

const ctrl = vscode.tests.createTestController(`${extensionId}`, 'Vitest')
const fileDiscoverer = registerDiscovery(ctrl, context)

const workspaceConfigs = await getVitestWorkspaceConfigs()
// enable run/debug/watch tests only if vitest version >= 0.12.0
Expand All @@ -50,6 +51,12 @@ export async function activate(context: vscode.ExtensionContext) {
return
}

const config = await fetchVitestConfig(workspaceConfigs)
if (!config) {
vscode.window.showWarningMessage('Cannot run tests: no Vitest config found.')
return
}
const fileDiscoverer = registerDiscovery(ctrl, context, config)
registerRunDebugWatchHandler(ctrl, workspaceConfigs, fileDiscoverer, context)
context.subscriptions.push(
ctrl,
Expand Down Expand Up @@ -83,8 +90,8 @@ function workspacesCompatibilityCheck(workspaceConfigs: VitestWorkspaceConfig[])
return true
}

function registerDiscovery(ctrl: vscode.TestController, context: vscode.ExtensionContext) {
const fileDiscoverer = new TestFileDiscoverer()
function registerDiscovery(ctrl: vscode.TestController, context: vscode.ExtensionContext, config: ResolvedConfig) {
const fileDiscoverer = new TestFileDiscoverer(config)
// run on refreshing test list
ctrl.refreshHandler = async () => {
await fileDiscoverer.discoverAllTestFilesInWorkspace(ctrl)
Expand Down
77 changes: 77 additions & 0 deletions src/pure/watch/vitestConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { effect, reactive } from '@vue/reactivity'
import type { ResolvedConfig } from 'vitest'
import getPort from 'get-port'
import { log } from '../../log'
import type { VitestWorkspaceConfig } from '../../config'
import { getConfig } from '../../config'
import { execWithLog, sanitizeFilePath } from '../utils'
import { createClient } from './ws-client'

async function connectAndFetchConfig(
{ port, url = `ws://localhost:${port}/__vitest_api__`, reconnectInterval, reconnectTries }: {
url?: string
port: number
reconnectInterval?: number
reconnectTries?: number
},
) {
let onFailedConnection: (() => void) | undefined
const client = createClient(url, {
reactive: reactive as any,
reconnectInterval,
reconnectTries,
onFailedConnection: () => onFailedConnection?.(),
})

return new Promise<ResolvedConfig>((resolve, reject) => {
onFailedConnection = () => reject(new Error ('Unable to connect to Vitest API'))
const handled = new WeakSet()
effect(() => {
const ws = client.ws
if (!handled.has(ws)) {
handled.add(ws)
ws.addEventListener('open', () => {
log.info('WS Opened')
client.rpc.getConfig().then((_config) => {
client.dispose()
resolve(_config)
})
})

ws.addEventListener('error', (e) => {
console.error('WS ERROR', e)
})

ws.addEventListener('close', () => {
log.info('WS Close')
})
}
})
})
}

export async function fetchVitestConfig(
workspaceConfigs: VitestWorkspaceConfig[],
) {
const port = await getPort()
const workspace = workspaceConfigs.find(workspace =>
workspace.isCompatible && !workspace.isDisabled && workspace.isUsingVitestForSure)
if (!workspace)
return
const folder = workspace.workspace.uri.fsPath
const childProcess = execWithLog(
workspace.cmd,
[...workspace.args, '--api.port', port.toString(), '--api.host', '127.0.0.1'],
{
cwd: sanitizeFilePath(folder),
env: { ...process.env, ...getConfig(folder).env },
},
).child
const config = await connectAndFetchConfig({
port,
reconnectInterval: 500,
reconnectTries: 20,
})
childProcess.kill()
return config
}
4 changes: 4 additions & 0 deletions src/pure/watch/ws-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export interface VitestClientOptions {
reactive?: <T>(v: T) => T
ref?: <T>(v: T) => { value: T }
WebSocketConstructor?: typeof WebSocket
onFailedConnection?: () => void
}

export interface VitestClient {
Expand All @@ -112,6 +113,7 @@ export function createClient(url: string, options: VitestClientOptions = {}) {
reconnectTries = 10,
reactive = v => v,
WebSocketConstructor = globalThis.WebSocket,
onFailedConnection,
} = options

let tries = reconnectTries
Expand Down Expand Up @@ -190,6 +192,8 @@ export function createClient(url: string, options: VitestClientOptions = {}) {
tries -= 1
if (!opened && autoReconnect && tries > 0)
setTimeout(reconnect, reconnectInterval)
else if (autoReconnect && tries === 0)
onFailedConnection?.()
})
}

Expand Down
7 changes: 4 additions & 3 deletions src/vscodeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { TextDecoder } from 'util'
import type { Uri } from 'vscode'
import { workspace } from 'vscode'
import minimatch from 'minimatch'
import { getConfig } from './config'
import type { ResolvedConfig } from 'vitest'
import { getCombinedConfig } from './config'

const textDecoder = new TextDecoder('utf-8')

Expand All @@ -17,8 +18,8 @@ export const getContentFromFilesystem = async (uri: Uri) => {
}
}

export function shouldIncludeFile(path: string) {
const { include, exclude } = getConfig()
export function shouldIncludeFile(path: string, config: ResolvedConfig) {
const { include, exclude } = getCombinedConfig(config)
return (
include.some(x => minimatch(path, x))
&& exclude.every(x => !minimatch(path, x, { dot: true }))
Expand Down

0 comments on commit d62ca01

Please sign in to comment.