Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137import type { BirpcOptions, BirpcReturn } from 'birpc'import { createBirpc } from 'birpc'import { parse, stringify } from 'flatted'
// eslint-disable-next-line no-restricted-importsimport type { WebSocketEvents, WebSocketHandlers } from 'vitest'import type { CancelReason } from '@vitest/runner'import { StateManager } from '../../vitest/src/node/state'
export * from '../../vitest/src/utils/tasks'
export interface VitestClientOptions { handlers?: Partial<WebSocketEvents> autoReconnect?: boolean reconnectInterval?: number reconnectTries?: number connectTimeout?: number reactive?: <T>(v: T) => T ref?: <T>(v: T) => { value: T } WebSocketConstructor?: typeof WebSocket}
export interface VitestClient { ws: WebSocket state: StateManager rpc: BirpcReturn<WebSocketHandlers, WebSocketEvents> waitForConnection: () => Promise<void> reconnect: () => Promise<void>}
export function createClient(url: string, options: VitestClientOptions = {}) { const { handlers = {}, autoReconnect = true, reconnectInterval = 2000, reconnectTries = 10, connectTimeout = 60000, reactive = v => v, WebSocketConstructor = globalThis.WebSocket, } = options
let tries = reconnectTries const ctx = reactive({ ws: new WebSocketConstructor(url), state: new StateManager(), waitForConnection, reconnect, }) as VitestClient
ctx.state.filesMap = reactive(ctx.state.filesMap) ctx.state.idMap = reactive(ctx.state.idMap)
let onMessage: Function const functions: WebSocketEvents = { onPathsCollected(paths) { ctx.state.collectPaths(paths) handlers.onPathsCollected?.(paths) }, onCollected(files) { ctx.state.collectFiles(files) handlers.onCollected?.(files) }, onTaskUpdate(packs) { ctx.state.updateTasks(packs) handlers.onTaskUpdate?.(packs) }, onUserConsoleLog(log) { ctx.state.updateUserLog(log) }, onFinished(files, errors) { handlers.onFinished?.(files, errors) }, onFinishedReportCoverage() { handlers.onFinishedReportCoverage?.() }, onCancel(reason: CancelReason) { handlers.onCancel?.(reason) }, }
const birpcHandlers: BirpcOptions<WebSocketHandlers> = { post: msg => ctx.ws.send(msg), on: fn => (onMessage = fn), serialize: stringify, deserialize: parse, onTimeoutError(functionName) { throw new Error(`[vitest-ws-client]: Timeout calling "${functionName}"`) }, }
ctx.rpc = createBirpc<WebSocketHandlers, WebSocketEvents>( functions, birpcHandlers, )
let openPromise: Promise<void>
function reconnect(reset = false) { if (reset) tries = reconnectTries ctx.ws = new WebSocketConstructor(url) registerWS() }
function registerWS() { openPromise = new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error(`Cannot connect to the server in ${connectTimeout / 1000} seconds`)) }, connectTimeout)?.unref?.() if (ctx.ws.OPEN === ctx.ws.readyState) resolve() // still have a listener even if it's already open to update tries ctx.ws.addEventListener('open', () => { tries = reconnectTries resolve() clearTimeout(timeout) }) }) ctx.ws.addEventListener('message', (v) => { onMessage(v.data) }) ctx.ws.addEventListener('close', () => { tries -= 1 if (autoReconnect && tries > 0) setTimeout(reconnect, reconnectInterval) }) }
registerWS()
function waitForConnection() { return openPromise }
return ctx}