Tests only protect you if they run before code ships. **Vitest** makes that easy on both ends: it's a fast, modern test runner that's pleasant to use locally, and it produces a clean pass/fail exit code you can wire straight into a deployment pipeline as a gate. This guide covers writing tests with Vitest and using them to stop a broken build from ever reaching production with DeployHQ.

## What is Vitest?

Vitest is a test runner built on top of Vite. If you've used Jest, you already know the API — `describe`, `it`, `expect` — but Vitest runs natively on ESM and TypeScript with no extra configuration, starts faster, and reuses your existing Vite config so tests run through the same transform pipeline as your app. For projects already using Vite (or a Vite-based framework), it's the natural test runner.

## Installing Vitest

```bash
npm install -D vitest
```

Add a test script to `package.json`. The distinction matters for deployment:

```json
{
  "scripts": {
    "test": "vitest run",
    "test:watch": "vitest"
  }
}
```

- `vitest` launches watch mode for local development — reruns on save.
- `vitest run` runs the suite once and **exits with a non-zero code if any test fails**. That exit code is what makes it a usable pipeline gate.

## Writing a test

Vitest picks up files named `*.test.ts` (or `.js`) automatically:

```ts
// sum.test.ts
import { describe, it, expect } from 'vitest'
import { sum } from './sum'

describe('sum', () => {
  it('adds two numbers', () => {
    expect(sum(2, 3)).toBe(5)
  })
})
```

Run it:

```bash
npm test
```

## Configuration and coverage

Vitest reads your existing `vite.config.ts`, or you can add a dedicated `vitest.config.ts`:

```ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    environment: 'node',        // or 'jsdom' for browser-like tests
    coverage: { provider: 'v8' }
  }
})
```

Then generate a coverage report with `vitest run --coverage`.

## Using Vitest as a deploy gate in DeployHQ

Here's where Vitest earns its place in a deployment guide. Because `vitest run` returns a failing exit code when a test fails, you can make a passing test suite a **precondition for deploying**.

Add the test step to your [build pipeline](https://www.deployhq.com/features/build-pipelines) before the build, and let a failure halt the deploy:

```bash
npm ci
npm test            # vitest run — non-zero exit stops the pipeline
npm run build
```

With the step set to halt on error, a failing test stops the pipeline and nothing broken ships. Enable [automatic deployments](https://www.deployhq.com/features/automatic-deployments) and every push is validated the same way: tests run, and only a green suite proceeds to build and deploy. The gate is automatic, so no one has to remember to run the tests before releasing.

## Pair it with a linter gate

Tests catch behavior regressions; a linter catches style and correctness issues before they even reach a test. Running both as pipeline gates is a common setup — add a [lint and format check with Biome](https://www.deployhq.com/guides/biome) alongside your Vitest step so a deploy has to pass both. To keep the commands identical between your machine and the pipeline, define them once with a [command runner like just](https://www.deployhq.com/guides/just).

Ready to make passing tests a requirement for every deploy? [Create a free DeployHQ account](https://www.deployhq.com/signup) and connect your repository in minutes.