docs/guide/in-source.md
Vitest provides a way to run tests within your source code along side the implementation, similar to Rust's module tests.
This makes the tests share the same closure as the implementations and able to test against private states without exporting. Meanwhile, it also brings a closer feedback loop for development.
::: warning This guide explains how to write tests inside your source code. If you need to write tests in separate test files, follow the "Writing Tests" guide. :::
To get started, put a if (import.meta.vitest) block at the end of your source file and write some tests inside it. For example:
// the implementation
export function add(...args: number[]) {
return args.reduce((a, b) => a + b, 0)
}
// in-source test suites
if (import.meta.vitest) {
const { it, expect } = import.meta.vitest
it('add', () => {
expect(add()).toBe(0)
expect(add(1)).toBe(1)
expect(add(1, 2, 3)).toBe(6)
})
}
Update the includeSource config for Vitest to grab the files under src/:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
includeSource: ['src/**/*.{js,ts}'], // [!code ++]
},
})
Then you can start to test!
$ npx vitest
For the production build, you will need to set the define options in your config file, letting the bundler do the dead code elimination. For example, in Vite
/// <reference types="vitest/config" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
includeSource: ['src/**/*.{js,ts}'],
},
define: { // [!code ++]
'import.meta.vitest': 'undefined', // [!code ++]
}, // [!code ++]
})
::: details Rolldown
import { defineConfig } from 'rolldown/config'
export default defineConfig({
transform: {
define: { // [!code ++]
'import.meta.vitest': 'undefined', // [!code ++]
}, // [!code ++]
},
})
Learn more: Rolldown :::
::: details Rollup
import replace from '@rollup/plugin-replace' // [!code ++]
export default {
plugins: [
replace({ // [!code ++]
'import.meta.vitest': 'undefined', // [!code ++]
}) // [!code ++]
],
// other options
}
Learn more: Rollup :::
::: details unbuild
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
replace: { // [!code ++]
'import.meta.vitest': 'undefined', // [!code ++]
}, // [!code ++]
// other options
})
Learn more: unbuild :::
::: details webpack
const webpack = require('webpack')
module.exports = {
plugins: [
new webpack.DefinePlugin({ // [!code ++]
'import.meta.vitest': 'undefined', // [!code ++]
})// [!code ++]
],
}
Learn more: webpack :::
To get TypeScript support for import.meta.vitest, add vitest/importMeta to your tsconfig.json:
{
"compilerOptions": {
"types": [
"vitest/importMeta" // [!code ++]
]
}
}
Reference to examples/in-source-test for the full example.
This feature could be useful for:
It's recommended to use separate test files instead for more complex tests like components or E2E testing.