|
| 1 | +import { rpc } from './rpc' |
| 2 | +import { importId } from './utils' |
| 3 | + |
| 4 | +const { Date, console } = globalThis |
| 5 | + |
| 6 | +export const setupConsoleLogSpy = async () => { |
| 7 | + const { stringify, format, utilInspect } = await importId('vitest/utils') as typeof import('vitest/utils') |
| 8 | + const { log, info, error, dir, dirxml, trace, time, timeEnd, timeLog, warn, debug, count, countReset } = console |
| 9 | + const formatInput = (input: unknown) => { |
| 10 | + if (input instanceof Node) |
| 11 | + return stringify(input) |
| 12 | + return format(input) |
| 13 | + } |
| 14 | + const processLog = (args: unknown[]) => args.map(formatInput).join(' ') |
| 15 | + const sendLog = (type: 'stdout' | 'stderr', content: string) => { |
| 16 | + if (content.startsWith('[vite]')) |
| 17 | + return |
| 18 | + const unknownTestId = '__vitest__unknown_test__' |
| 19 | + // @ts-expect-error untyped global |
| 20 | + const taskId = globalThis.__vitest_worker__?.current?.id ?? unknownTestId |
| 21 | + rpc().sendLog({ |
| 22 | + content, |
| 23 | + time: Date.now(), |
| 24 | + taskId, |
| 25 | + type, |
| 26 | + size: content.length, |
| 27 | + }) |
| 28 | + } |
| 29 | + const stdout = (base: (...args: unknown[]) => void) => (...args: unknown[]) => { |
| 30 | + sendLog('stdout', processLog(args)) |
| 31 | + return base(...args) |
| 32 | + } |
| 33 | + const stderr = (base: (...args: unknown[]) => void) => (...args: unknown[]) => { |
| 34 | + sendLog('stderr', processLog(args)) |
| 35 | + return base(...args) |
| 36 | + } |
| 37 | + console.log = stdout(log) |
| 38 | + console.debug = stdout(debug) |
| 39 | + console.info = stdout(info) |
| 40 | + |
| 41 | + console.error = stderr(error) |
| 42 | + console.warn = stderr(warn) |
| 43 | + |
| 44 | + console.dir = (item, options) => { |
| 45 | + sendLog('stdout', utilInspect(item, options)) |
| 46 | + return dir(item, options) |
| 47 | + } |
| 48 | + |
| 49 | + console.dirxml = (...args) => { |
| 50 | + sendLog('stdout', processLog(args)) |
| 51 | + return dirxml(...args) |
| 52 | + } |
| 53 | + |
| 54 | + console.trace = (...args: unknown[]) => { |
| 55 | + const content = processLog(args) |
| 56 | + const error = new Error('Trace') |
| 57 | + const stack = (error.stack || '').split('\n').slice(2).join('\n') |
| 58 | + sendLog('stdout', `${content}\n${stack}`) |
| 59 | + return trace(...args) |
| 60 | + } |
| 61 | + |
| 62 | + const timeLabels: Record<string, number> = {} |
| 63 | + |
| 64 | + console.time = (label = 'default') => { |
| 65 | + const now = performance.now() |
| 66 | + time(label) |
| 67 | + timeLabels[label] = now |
| 68 | + } |
| 69 | + |
| 70 | + console.timeLog = (label = 'default') => { |
| 71 | + timeLog(label) |
| 72 | + if (!(label in timeLabels)) |
| 73 | + sendLog('stderr', `Timer "${label}" does not exist`) |
| 74 | + else |
| 75 | + sendLog('stdout', `${label}: ${timeLabels[label]} ms`) |
| 76 | + } |
| 77 | + |
| 78 | + console.timeEnd = (label = 'default') => { |
| 79 | + const end = performance.now() |
| 80 | + timeEnd(label) |
| 81 | + const start = timeLabels[label] |
| 82 | + if (!(label in timeLabels)) { |
| 83 | + sendLog('stderr', `Timer "${label}" does not exist`) |
| 84 | + } |
| 85 | + else if (start) { |
| 86 | + const duration = end - start |
| 87 | + sendLog('stdout', `${label}: ${duration} ms`) |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + const countLabels: Record<string, number> = {} |
| 92 | + |
| 93 | + console.count = (label = 'default') => { |
| 94 | + const counter = (countLabels[label] ?? 0) + 1 |
| 95 | + countLabels[label] = counter |
| 96 | + sendLog('stdout', `${label}: ${counter}`) |
| 97 | + return count(label) |
| 98 | + } |
| 99 | + |
| 100 | + console.countReset = (label = 'default') => { |
| 101 | + countLabels[label] = 0 |
| 102 | + return countReset(label) |
| 103 | + } |
| 104 | +} |
0 commit comments