--- title: Debugging Failing Tests | Guide prev: text: Testing in Practice link: /guide/learn/testing-in-practice next: text: Writing Tests with AI link: /guide/learn/writing-tests-with-ai --- # Debugging Failing Tests This page covers how to investigate test failures in Vitest: reading error output, isolating problems, identifying common causes, and using the available debugging tools. ## Reading the Error When a test fails, Vitest gives you several pieces of information. Let's look at a real failure and break it down: <<< ./snippets/debug-output-fail.ansi There's a lot here, but each part tells you something: **The header** (`FAIL src/user.test.js > createUser > sets the default role`) tells you which file, describe block, and test failed. This is the full path in the test tree. **The assertion message** (`expected { ... } to deeply equal { ... }`) tells you what kind of check failed and shows the two values being compared. **The diff** shows exactly what's different. Lines starting with + are what you actually got, and lines starting with - are what you expected. In this case, the role was "viewer" but the test expected "member". **The code snippet** shows the exact line and a few surrounding lines, with a caret (`^`) pointing to the failing assertion. You can click the file path in most terminals and IDEs to jump directly there. At this point, the question is: did the code change (maybe the default role was intentionally updated to `"viewer"`), or is the test wrong? Check the source code for `createUser` to find out. If the default was intentionally changed, update the test. If not, you've found a bug. ## Isolating the Problem When a test fails and the cause isn't immediately clear, the first step is to isolate it. Run just that one test, without the rest of your suite: ```bash # Run only the failing test file vitest src/user.test.js # Run only tests matching a name pattern vitest -t "sets the default role" # Combine both for maximum precision vitest src/user.test.js -t "sets the default role" ``` You can also add [`.only`](/api/test#only) to the test itself: ```js test.only('sets the default role', () => { // only this test runs in the file }) ``` If you have many failures and want to focus on the first one, use [`--bail`](/config/bail) to stop after a set number of failures: ```bash vitest --bail 1 ``` If the test passes when run alone but fails when run with others, you have a test isolation problem (more on that below). If it fails even when run alone, the issue is in the test itself or the code it's testing. ## Common Causes of Failures ### Shared State Between Tests This is one of the most common and frustrating issues. A test passes when you run it alone, but fails when the full suite runs. The usual cause is that some other test modifies shared state (a global variable, a module-level cache, a database) and doesn't clean up after itself. ```js // This is a problem: `users` is shared between tests const users = [] test('adds a user', () => { users.push('Alice') expect(users).toEqual(['Alice']) }) test('starts empty', () => { // This fails because 'Alice' is still in the array! expect(users).toEqual([]) }) ``` The fix is to reset the state before each test with [`beforeEach`](/api/hooks#beforeeach), or better yet, use [`test.extend`](/guide/test-context#extend-test-context) to create fresh state for each test automatically: ```js const test = baseTest.extend('users', () => []) test('adds a user', ({ users }) => { users.push('Alice') expect(users).toEqual(['Alice']) }) test('starts empty', ({ users }) => { // Passes: each test gets its own array expect(users).toEqual([]) }) ``` ### Async Issues Tests that involve promises can fail intermittently or in confusing ways if the async flow isn't handled correctly. The most common mistake is forgetting an `await`: ```js // This test always passes, even if fetchUser rejects! test('fetches user', () => { // Missing await: the test finishes before the promise settles expect(fetchUser(1)).resolves.toMatchObject({ name: 'Alice' }) }) ``` Vitest will usually warn you about unawaited assertions at the end of the test. If you see that warning, add the missing `await`: ```js test('fetches user', async () => { await expect(fetchUser(1)).resolves.toMatchObject({ name: 'Alice' }) }) ``` If a test hangs and eventually times out, it usually means a promise never resolves. Check for missing callbacks, unresolved conditions, or deadlocks in the code you're testing. ### Stale Snapshots If you're using [snapshot tests](/guide/learn/snapshots) and you intentionally changed the output of your code, the existing snapshots will be outdated. The test fails and shows a diff between the old snapshot and the new output. This is expected. Review the diff to confirm the changes are correct, then update the snapshots by pressing `u` in watch mode or running `vitest -u`. ### Wrong Test Environment If your code accesses browser APIs like `document` or `window` and you see errors like "document is not defined", your test is running in the Node environment (the default). You can switch to a browser-like environment with the [`environment`](/config/environment) config option, or better yet, use [Browser Mode](/guide/browser/) which runs tests in a real browser. ### Mocks Not Cleaned Up If a mock from one test leaks into another, you'll get unexpected behavior. For example, a `vi.spyOn` that overrides a method's return value will persist into the next test unless it's restored. The easiest fix is to enable automatic mock restoration in your config: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { restoreMocks: true, }, }) ``` This calls [`mockRestore()`](/api/mock#mockrestore) on every mock after each test. See the [Mock Functions](/guide/learn/mock-functions#resetting-mocks) tutorial for more details. ## Debugging Tools ### Console Logging There's nothing wrong with adding `console.log` to your tests. It's the fastest way to inspect values and understand what's happening: ```js test('transforms data correctly', () => { const input = getData() console.log('input:', input) const result = transform(input) console.log('result:', result) expect(result).toMatchObject({ status: 'ok' }) }) ``` Vitest displays console output inline with the test results, so you can see which test produced which log. ### Vitest UI For a visual overview of your test suite, run Vitest with the `--ui` flag: ```bash vitest --ui ``` This opens a browser-based dashboard where you can see all your tests, their status, and their output. It also includes a module graph that shows how your files are connected, which can help you understand why a change in one file causes failures in another. See the [Vitest UI](/guide/ui) guide for more details. ### VS Code Extension The [Vitest VS Code extension](https://vitest.dev/vscode) lets you run and debug individual tests directly from your editor. You can click a "play" button next to any test, set breakpoints, and step through code in the VS Code debugger. This is often faster than switching between the terminal and your editor. ### Verbose Output If the default output isn't showing enough detail, use the verbose reporter: ```bash vitest --reporter=verbose ``` This shows every test individually (not just the files), which can help spot patterns in which tests pass and which fail. ### Attaching a Debugger For more complex issues where you need to step through code line by line, you can run Vitest with the `--inspect-brk` flag and attach a debugger. The `--no-file-parallelism` flag ensures tests run in the main thread so breakpoints work reliably: ```bash vitest --inspect-brk --no-file-parallelism ``` Then attach from VS Code, IntelliJ, or Chrome DevTools (`chrome://inspect`). See the [Debugging](/guide/debugging) guide for detailed setup instructions for each editor. ## Getting Help If you're stuck, these resources can help: - The [Common Errors](/guide/common-errors) page covers specific error messages and their solutions - [GitHub Issues](https://github.com/vitest-dev/vitest/issues) for searching known bugs and workarounds - The [Discord community](https://chat.vitest.dev) for real-time help from other Vitest users and maintainers