Skip to content

Conversation

@GermanJablo
Copy link

Problem

Prior to this pull request, the test results panel only displayed the console.logs that occurred during the test.
Clicking on the test instance in the right panel displays the expected and actual values ​​in separate boxes, along with a series of traces. However, this format is divided into different terminals, making it difficult to copy and paste, or even to read (for both humans and AI).

Solution

With this PR, two things are displayed:

  1. The first line shows the command to replicate in the CLI.
  2. Then, the complete test output, as defined in the user configuration's reporters.

Before:

image

After:

image

Changes

1. runner.ts - Preserve ANSI colors & clean output

  • Remove stripVTControlCharacters(): VS Code's Test Results panel supports ANSI escape codes for colors
  • Delay TestRun cleanup: Prevents premature closure of the output stream while async results are still arriving
  • Clean output: Automatically strips Vitest's watch mode prompts ("Watching for file changes...") to keep the log focused on results
  • Show CLI command: Displays the equivalent command for easy reproducibility from the terminal
  • Skip duplicate console.logs: Avoids double-printing logs that reporters already handles

2. rpc.ts - Add persistent onProcessLog handler

  • Create and preserve handler: Output from worker arrives via RPC. If the handler is cleared between runs, subsequent executions have nowhere to send stdout/stderr

3. child_process.ts - Connect RPC to stdout callbacks

  • Forward onProcessLog to callbacks: The worker sends output via WebSocket/RPC, not Node's native stdout. This bridges RPC events to the stdout callback system

4. worker/index.ts - Enable DefaultReporter

  • Add 'default' reporter: Run Vitest's DefaultReporter alongside VSCodeReporter to get CLI-style output
  • Respect user reporters: If user has custom reporters configured (e.g., reporters: ['verbose']), those are used instead of 'default'

Minor Formatting Differences

Due to the way Vitest's detects terminal environments, there are small formatting differences compared to CLI output:

  • Extension (without TTY): No suite hierarchy (e.g., ❯ addition (9) not shown)
  • columns/separators: the number of columns available in the terminal, used for example in separators, is not calculated.

Comment on lines +431 to +443

// Show the equivalent CLI command for debugging/reproducibility
const fileList = files.map(f => this.relative(f)).join(' ')
const pattern = formatTestPattern(request.include || [])
let vitestCmd = 'vitest'
if (fileList) {
vitestCmd += ` ${fileList}`
}
if (pattern) {
vitestCmd += ` -t "${pattern}"`
}
run.appendOutput(`\x1B[36m\x1B[1m[command]\x1B[0m ${vitestCmd}\r\n\r\n`)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nice to have in the first line:

Image

Inspired by this Jest extension

Copy link
Member

@sheremet-va sheremet-va Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how the extension works, we don't create a new process for every test run. Even more, I am planning to change to the new project.createSpecification API that supports test ids, making this line useless


function formatTestOutput(output: string) {
return stripVTControlCharacters(output.replace(/(?<!\r)\n/g, '\r\n'))
return output.replace(/(?<!\r)\n/g, '\r\n')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test results panel in VSCode / Cursor supports colors. No need to remove them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colors are not supported in inline view, at least

Copy link
Member

@sheremet-va sheremet-va left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes seems to break things rather than fix them. Please open an issue with the desired functionality, it needs to be discussed first

// run the next test when this one finished, or cancell or test runs if they were cancelled
this.testRunDefer.promise = this.testRunDefer.promise.finally(() => {
run.end()
this.testRun = undefined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

clearListeners() {
for (const name in handlers)
handlers[name as 'onCollected']?.clear()
// Clear all handlers except onProcessLog, which needs to persist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do this? the handlers are not cleaned after the test run, they are cleaned when the fork is destroyed, onProcessLog needs to be cleaned

stdoutCallbacks.clear()
}

// Forward RPC process logs to the same stdout callbacks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

})

// Skip individual console logs since DefaultReporter already includes them
// api.onConsoleLog((consoleLog) => { ... }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

stderr,
stdout,
},
)
Copy link
Member

@sheremet-va sheremet-va Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? This makes it so unhandled errors outside of tests are not reporter (failed global setup, for example)

['json', { ...jsonReporterOptions, file: meta.finalCoverageFileName }],
]

const rawReporters = testConfig.reporters
Copy link
Member

@sheremet-va sheremet-va Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We intentionally don't show the report since vscode already has the UI to show everything. It is a waste of resources to duplicate it

The extension also doesn't support the same hooks order, so custom reporters might break

If the intention is to help AI, then it is better to have a custom reporter designed for that (to reduce the amount of tokens, at least) or something like this: #676


testRun.appendOutput(
formatTestOutput(consoleLog.content) + (consoleLog.browser ? '\r\n' : ''),
location,
Copy link
Member

@sheremet-va sheremet-va Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change logs are no longer attributed to tests and are not shown inline in UI

// Signal that the test run is complete, but DON'T set this.testRun to undefined yet
// The testRun will be properly ended in the finally block of startTestRun
if (!collecting) {
this.testRunDefer?.resolve()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why replace this.endTestRun with an incomplete promise resolution?

@GermanJablo
Copy link
Author

These changes seems to break things rather than fix them. Please open an issue with the desired functionality, it needs to be discussed first

Thanks for the thorough review! You're right, I rushed the PR, and there might be things I'm not addressing correctly.

I've opened this issue hoping we can agree on the "why" before moving on to the "how."

Thank you so much for your time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants