Skip to content

vitest-dev/vitest

Repository files navigation

Vitest

A blazing fast unit test framework powered by Vite.

💖 This project is currently in closed beta exclusively for Sponsors.
Become a Sponsor of @patak-js or @antfu to access the source code and issues tracker.

⚠️ DISCLAIMER: Vitest is still in development and not stable yet. It's not recommended to use it in production.

Vitest requires Vite v2.7 and Node v16

Join the Discord!

Features

  • Vite's config, transformers, resolvers, and plugins. Use the same setup from your app!
  • Jest Snapshot
  • Chai built-in for assertions, with jest-expect compatible APIs.
  • Smart watch mode, just like HMR for tests!
  • Code coverage
  • Sinon built-in for mocking
  • JSDOM built-in for DOM and browser API mocking
  • Components testing (Vue example, React example)
  • Async suite / test, top level await
  • ESM friendly
  • Out-of-box TypeScript / JSX support
  • Suite and Test filtering (skip, only, todo)
  • Concurrent Tests
import { it, describe, expect, assert } from 'vitest'

describe('suite name', () => {
  it('foo', () => {
    expect(1 + 1).toEqual(2)
    expect(true).to.be.true
  })

  it('bar', () => {
    assert.equal(Math.sqrt(4), 2)
  })

  it('snapshot', () => {
    expect({ foo: 'bar' }).toMatchSnapshot()
  })
})
$ npx vitest

Examples

Configuration

vitest will read your root vite.config.ts when it present to match with the plugins and setup as your Vite app. If you want to it to have a different configuration for testing, you could either:

  • Create vitest.config.ts, which will have the higher priority
  • Pass --config option to CLI, e.g. vitest --config ./path/to/vitest.config.ts
  • Use process.env.VITEST to conditionally apply differnet configuration in vite.config.ts

To configure vitest itself, add test property in your Vite config

// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    // ...
  }
})

Global APIs

By default, vitest does not provide global APIs for explicitness. If you prefer to use the APIs globally like Jest, you can pass the --global option to CLI or add global: true in the config.

// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    global: true
  }
})

To get TypeScript working with the global APIs, add vitest/global to the types filed in your tsconfig.json

// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "vitest/global"
    ]
  }
}

Browser Mocking

Pass --dom option in CLI to enable browser mocking. Or the dom flag in the config.

// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    dom: true
  }
})

Vitest by default uses jsdom for mocking, but it also support happy-dom, a faster alternative to jsdom. You can configure it with:

// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    dom: 'happy-dom'
  }
})

Watch Mode

$ vitest -w

Vitest smartly searches the module graph and only rerun the related tests (just like how HMR works in Vite!).

Coverage

Vitest works perfectly with c8

$ c8 vitest
{
  "scripts": {
    "test": "vitest",
    "coverage": "c8 vitest"
  }
}

For convenience, we also provide a shorthand for passing --coverage option to CLI, which will wrap the process with c8 for you. Note when using the shorthand, you will lose the ability to pass additional options to c8.

$ vitest --coverage

For more configuration available, please refer to c8's documentation.

Filtering

CLI

You can use CLI to filter test files my name:

$ vitest basic

Will only execute test files that contain basic, e.g.

basic.test.ts
basic-foo.test.ts

Skipping suites and tasks

Use .skip to avoid running certain suites or tests

describe.skip('skipped suite', () => {
  it('task', () => {
    // Suite skipped, no error
    assert.equal(Math.sqrt(4), 3)
  })
})

describe('suite', () => {
  it.skip('skipped task', () => {
    // Task skipped, no error
    assert.equal(Math.sqrt(4), 3)
  })
})

Selecting suites and tests to run

Use .only to only run certain suites or tests

// Only this suite (and others marked with only) are run
describe.only('suite', () => {
  it('task', () => {
    assert.equal(Math.sqrt(4), 3) 
  })
})

describe('another suite', () => {
  it('skipped task', () => {
     // Task skipped, as tests are running in Only mode
    assert.equal(Math.sqrt(4), 3)
  })

  it.only('task', () => {
     // Only this task (and others marked with only) are run
    assert.equal(Math.sqrt(4), 2)
  })
})

Unimplemented suites and tests

Use .todo to stub suites and tests that should be implemented

 // An entry will be shown in the report for this suite
describe.todo('unimplemented suite')

// An entry will be shown in the report for this task
describe('suite', () => {
  it.todo('unimplemented task')
})

Running tests concurrently

Use .concurrent in consecutive tests to run them in parallel

// The two tasks marked with concurrent will be run in parallel
describe('suite', () => {
  it('serial task', () => {
    assert.equal(Math.sqrt(4), 3)
  })
  it.concurrent('concurrent task 1', () => {
    assert.equal(Math.sqrt(4), 3)
  })
  it.concurrent('concurrent task 2', () => {
    assert.equal(Math.sqrt(4), 3)
  })
})

If you use .concurrent in a suite, every tasks in it will be run in parallel

// The two tasks marked with concurrent will be run in parallel
describe.concurrent('suite', () => {
  it('concurrent task 1', () => {
    assert.equal(Math.sqrt(4), 3)
  })
  it('concurrent task 2', () => {
    assert.equal(Math.sqrt(4), 3)
  })
  // No effect, same as not using .concurrent
  it.concurrent('concurrent task 3', () => {
    assert.equal(Math.sqrt(4), 3)
  })
})

You can also use .skip, .only, and .todo with concurrent suite and tasks. All the following combinations are valid:

describe.concurrent(...)

describe.skip.concurrent(...)
describe.concurrent.skip(...)

describe.only.concurrent(...)
describe.concurrent.only(...)

describe.todo.concurrent(...)
describe.concurrent.todo(...)

it.concurrent(...)

it.skip.concurrent(...)
it.concurrent.skip(...)

it.only.concurrent(...)
it.concurrent.only(...)

it.todo.concurrent(...)
it.concurrent.todo(...)

Sponsors

Credits

Thanks to:

  • @patak-js for the awesome package name!
  • The Vite team for brainstorming the initial idea.
  • @pi0 for the idea and implementation of using Vite to transform and bundle the server code.
  • @lukeed for the work on uvu where we are inspired a lot from.

License

MIT License © 2021 Anthony Fu