Vitest Testing Framework
repository·main·Indexed 12 days ago
https://github.com/vitest-dev/vitestA Vite-native testing framework providing a fast, modern experience for unit, component, and browser testing with a Jest-compatible API. Version 5.0.0-rc.1 includes support for Hot Module Replacement (HMR), OpenTelemetry tracing, and specialized packages for browser providers (Playwright, WebdriverIO, Preview), snapshot testing, and Web Worker simulation.
What's inside Vitest
- Vitest is a next-generation testing framework powered by Vite. It is designed to provide a fast, modern testing experience, leveraging Vite's transformation capabilities to handle various file types and module systems efficiently.
What is Vitest?
mainVitest is a next-generation testing framework powered by Vite. It is designed to be fast and compatible with the Vite ecosystem, allowing you to use the same configuration, transformers, resolvers, and plugins from your application in your tests. It provides a Jest-compatible API, making it easy to migrate from Jest while benefiting from Vite's speed and features like HMR-style watch mode.Component Testing in Vitest
mainComponent testing focuses on verifying individual UI components in isolation. It sits between unit tests and end-to-end tests, providing faster feedback and easier debugging than E2E tests while offering more accurate environments than DOM simulations when used with Browser Mode.
Vitest supports multiple frameworks including Vue, React, Svelte, Lit, Preact, Qwik, Solid, Marko, and more.
Component Testing Hierarchy
When planning your test suite, prioritize coverage in this order:
- Critical User Paths: Always test these.
- Error Handling: Test failure scenarios.
- Edge Cases: Empty data, extreme values.
- Accessibility: Screen readers, keyboard navigation.
- Performance: Large datasets, animations.
Key features of Vitest
mainVitest includes a wide range of built-in features for modern web development:
- Vite Integration: Uses your existing Vite config, transformers, and plugins.
- Assertion Styles: Built-in Chai assertions with Jest
expectcompatibility. - Watch Mode: Smart and instant watch mode similar to HMR.
- Code Coverage: Native coverage via
v8oristanbul. - Mocking: Jest-compatible mocking, stubbing, and spies.
- DOM Mocking: Support for
JSDOMandhappy-dom. - Browser Mode: Run component tests (Vue, React, Svelte, Lit, Marko) natively in the browser.
- Type Testing: Support for
expect-typefor type-level testing. - Advanced Testing: Benchmarking (via Tinybench), Projects support, Sharding, and ESM-first architecture with top-level await.
Choose the right Vitest browser package
mainThe
@vitest/browserpackage is specifically designed for developers who want to create their own custom browser provider.If your goal is simply to run your existing tests in a real browser environment, you should use one of the following pre-built packages instead:
@vitest/browser-playwright: Use this to run tests using Playwright.@vitest/browser-webdriverio: Use this to run tests using WebdriverIO.@vitest/browser-preview: Use this to visualize how your tests appear in a real browser.
How project configuration resolution works
mainWhen using Vitest projects, configuration is resolved through a hierarchy of inputs.
Root Configuration Priority
The root configuration is resolved in this order (highest priority last):
- The root config file
viteOverrides(merged on top of the config file)- CLI options (
options, applied on top of everything else)
Project Inheritance
- Config files/directories: Resolve only their own file and do not inherit from the root configuration.
- Inline projects: Inherit the root configuration by default. The root config file is re-executed,
viteOverridesare merged, and then the project's own options are merged. extends: false: The inline project resolves only its own options.extends: './path': The referenced file is re-executed instead of the root config, andviteOverridesare not merged.
Exclusions from Inheritance
The following options from
viteOverridesare never inherited by projects:plugins: Plugin instances inviteOverridesbelong to the root server and cannot be shared.test.browser: Describes instances of a single project.test.tagsFilter: Applies to the whole run.nameandprojects.globalSetup(as it runs once per test run).
Global Options
Regardless of inheritance, these groups reach every project:
- CLI options for test execution:
--testTimeout,--retry,--pool, etc. - Run-level options:
coverage,attachmentsDir, andmergeReportsLabelfrom the root's resolved config.
Understand the limitations of the Browser Preview provider
mainThe
previewprovider is designed for visual inspection of tests in a real browser, but it lacks the automation depth of providers like Playwright or WebdriverIO.Key limitations include:
- No Headless Mode: The browser window will always be visible.
- Single Instance Constraint: You cannot run multiple instances of the same browser; each instance in the
instancesarray must use a different browser type. - Limited Configuration: You can only specify the browser name; advanced browser capabilities or options are not supported.
- No Low-Level Control: It does not support CDP (Chrome DevTools Protocol) commands or other low-level interactions.
- Interactivity API: The
userEventAPI is a re-export from@testing-library/user-eventand does not feature special integration with the browser instance.
Use type-aware lifecycle hooks with test.extend
mainWhen using
test.extendto add custom context, you can now reference lifecycle hooks likebeforeEachandafterEachdirectly on the returnedtestobject. These hooks are aware of the extended context provided by the extension.import { test as baseTest } from 'vitest' const test = baseTest.extend<{ todos: number[] }>({ todos: async ({}, use) => { await use([]) }, }) // These hooks are aware of the extended context test.beforeEach(({ todos }) => { todos.push(1) }) test.afterEach(({ todos }) => { console.log(todos) })Manage nested suite hook execution
mainWhen using nested
describeblocks, Vitest follows a hierarchical pattern where parent hooks wrap child hooks.The pattern follows:
- Parent
aroundAllwraps the entire suite (including children). - Parent
aroundEachwraps childaroundEachhooks. - Parent
beforeEachwraps childbeforeEachhooks. - Child hooks execute, then parent
afterEachhooks execute. - Finally, parent
afterAllandaroundAllcleanup occur.
describe('outer', () => { aroundAll(async (runSuite) => { console.log('outer aroundAll before') await runSuite() console.log('outer aroundAll after') }) beforeAll(() => console.log('outer beforeAll')) aroundEach(async (runTest) => { console.log('outer aroundEach before') await runTest() console.log('outer aroundEach after') }) beforeEach(() => console.log('outer beforeEach')) test('outer test', () => console.log('outer test')) describe('inner', () => { aroundAll(async (runSuite) => { console.log('inner aroundAll before') await runSuite() console.log('inner aroundAll after') }) beforeAll(() => console.log('inner beforeAll')) aroundEach(async (runTest) => { console.log('inner aroundEach before') await runTest() console.log('inner aroundEach after') }) beforeEach(() => console.log('inner beforeEach')) test('inner test', () => console.log('inner test')) afterEach(() => console.log('inner afterEach')) afterAll(() => console.log('inner afterAll')) }) afterEach(() => console.log('outer afterEach')) afterAll(() => console.log('outer afterAll')) })- Parent
What are Vitest pools and how do they work?
mainVitest runs tests within a 'pool'. A pool manages the execution environment and isolation for your tests. Vitest provides several built-in pool runners:
threads: Usesnode:worker_threadsfor isolation via a new worker context.forks: Usesnode:child_processfor isolation via a newchild_process.forkprocess.vmThreads: Usesnode:worker_threadsbut provides isolation using thevmmodule instead of a new worker context.browser: Runs tests using browser providers.typescript: Runs typechecking on tests.
Custom pools are an advanced, experimental, and low-level API primarily intended for library authors who need to control the lifecycle and communication of test workers.
Understand the Benchmark Provider lifetime
mainVitest imports the provider module on its first use and caches the default export for the entire lifetime of the worker.
Because there are no explicit
setuporteardownhooks in theBenchmarkProviderAPI, any state that needs to persist across multiple benchmark runs should be stored directly on the provider object itself (worker-scoped state).Compare watchTriggerPatterns and forceRerunTriggers
mainBoth
watchTriggerPatternsandforceRerunTriggersallow you to rerun tests when files outside the import graph change, but they behave differently:watchTriggerPatterns: Reruns only the specific tests you map for a given pattern. This is more efficient and keeps the watch loop fast.forceRerunTriggers: Reruns every test in your project whenever any file matching the pattern changes.
Use
watchTriggerPatternswhen you can precisely identify which tests depend on which files, and useforceRerunTriggersfor broader, less specific dependencies.