### Example Vitest Setup File
Source: https://main.vitest.dev/config/setupfiles
This example demonstrates how to use a setup file to initialize a testing library's configuration and perform a heavy computation only once. It also includes an `afterEach` hook for cleanup and a global variable to track initialization.
```typescript
import { config } from '@some-testing-lib'
if (!globalThis.setupInitialized) {
config.plugins = [myCoolPlugin]
computeHeavyThing()
globalThis.setupInitialized = true
}
// hooks reset before each test file
afterEach(() => {
cleanup()
})
globalThis.resetBeforeEachTest = true
```
--------------------------------
### Setup File with AfterEach Hook
Source: https://main.vitest.dev/guide/lifecycle
Execute setup files before each test file to initialize global state or register hooks. This example registers an `afterEach` hook for cleanup.
```typescript
import { afterEach } from 'vitest'
// Runs before each test file
console.log('Setup file executing')
// Register hooks that apply to all tests
afterEach(() => {
cleanup()
})
```
--------------------------------
### Complex Fixture Setup and Cleanup
Source: https://main.vitest.dev/guide/test-context
This example shows how to set up and clean up more complex fixtures, such as a database connection and test user, using `onCleanup` for both file-scoped and test-scoped fixtures.
```typescript
const test = baseTest
.extend('database', { scope: 'file' }, async ({}, { onCleanup }) => {
const db = await createDatabase()
await db.connect()
onCleanup(async () => {
await db.disconnect()
})
return db
})
.extend('user', async ({ database }, { onCleanup }) => {
const user = await database.createTestUser()
onCleanup(async () => {
await database.deleteUser(user.id)
})
return user
})
```
--------------------------------
### Start Vitest Programmatically
Source: https://main.vitest.dev/guide/advanced/tests
Use `startVitest` to initiate Vitest, validate installations, and run tests immediately. It returns a Vitest instance for further interaction.
```typescript
import { startVitest } from 'vitest/node'
const vitest = await startVitest(
'test',
[], // CLI filters
{},
{},
{},
)
const testModules = vitest.state.getTestModules()
for (const testModule of testModules) {
console.log(testModule.moduleId, testModule.ok() ? 'passed' : 'failed')
}
```
--------------------------------
### Global Setup with Named Exports
Source: https://main.vitest.dev/config/globalsetup
Use named `setup` and `teardown` functions for global setup and cleanup. The `setup` function receives the test project.
```js
export function setup(project) {
console.log('setup')
}
export function teardown() {
console.log('teardown')
}
```
--------------------------------
### Manual Installation of Preview Provider with bun
Source: https://main.vitest.dev/guide/browser
Install Vitest and the browser preview provider manually using bun.
```bash
bun add -D vitest @vitest/browser-preview
```
--------------------------------
### Manual Installation of Preview Provider with yarn
Source: https://main.vitest.dev/guide/browser
Install Vitest and the browser preview provider manually using yarn.
```bash
yarn add -D vitest @vitest/browser-preview
```
--------------------------------
### Manual Installation of Preview Provider with npm
Source: https://main.vitest.dev/guide/browser
Install Vitest and the browser preview provider manually using npm.
```bash
npm install -D vitest @vitest/browser-preview
```
--------------------------------
### Manual Installation of Preview Provider with pnpm
Source: https://main.vitest.dev/guide/browser
Install Vitest and the browser preview provider manually using pnpm.
```bash
pnpm add -D vitest @vitest/browser-preview
```
--------------------------------
### Global Setup with Default Export
Source: https://main.vitest.dev/config/globalsetup
Export a default function that returns a teardown function for global setup and cleanup. The setup function receives the test project.
```js
export default function setup(project) {
console.log('setup')
return function teardown() {
console.log('teardown')
}
}
```
--------------------------------
### One-Time Setup with beforeAll/afterAll
Source: https://main.vitest.dev/guide/learn/setup-teardown
Employ `beforeAll` for expensive, one-time setup (e.g., database connection) before any tests run, and `afterAll` for cleanup after all tests in the file have completed.
```javascript
import { afterAll, beforeAll, expect, test } from 'vitest'
let db
beforeAll(async () => {
db = await connectToDatabase()
})
afterAll(async () => {
await db.close()
})
test('can query users', async () => {
const users = await db.query('SELECT * FROM users')
expect(users.length).toBeGreaterThan(0)
})
test('can query products', async () => {
const products = await db.query('SELECT * FROM products')
expect(products.length).toBeGreaterThan(0)
})
```
--------------------------------
### Install Vitest with bun
Source: https://main.vitest.dev/guide
Install Vitest as a development dependency using bun.
```bash
bun add -D vitest
```
--------------------------------
### Plugin Implementation Examples
Source: https://main.vitest.dev/api/advanced/plugin
Examples demonstrating how to implement a Vitest plugin, showing variations for Vitest-only and Vite+Vitest compatible plugins.
```APIDOC
::: code-group
```ts [only vitest]
import type { Vite, VitestPluginContext } from 'vitest/node'
export function plugin(): Vite.Plugin {
return {
name: 'vitest:my-plugin',
configureVitest(context: VitestPluginContext) {
// ...
}
}
}
```
```ts [vite and vitest]
///
import type { Plugin } from 'vite'
export function plugin(): Plugin {
return {
name: 'vitest:my-plugin',
transform() {
// ...
},
configureVitest(context) {
// ...
}
}
}
```
:::
```
--------------------------------
### Example DOM structure
Source: https://main.vitest.dev/api/browser/locators
This is an example HTML structure used to demonstrate `getByRole` functionality.
```html
Sign up
```
--------------------------------
### OpenTelemetry SDK Configuration (otel.js)
Source: https://main.vitest.dev/config/experimental
Example of an OpenTelemetry SDK file that exposes a started SDK instance as a default export. This file is imported by Vitest when `sdkPath` is configured.
```javascript
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
import { NodeSDK } from '@opentelemetry/sdk-node'
const sdk = new NodeSDK({
serviceName: 'vitest',
traceExporter: new OTLPTraceExporter(),
instrumentations: [getNodeAutoInstrumentations()],
})
sdk.start()
export default sdk
```
--------------------------------
### Install Vitest with pnpm
Source: https://main.vitest.dev/guide
Install Vitest as a development dependency using pnpm.
```bash
pnpm add -D vitest
```
--------------------------------
### Install Istanbul Coverage Package
Source: https://main.vitest.dev/guide/coverage
Install the Istanbul coverage support package using npm.
```bash
npm i -D @vitest/coverage-istanbul
```
--------------------------------
### Install Vitest UI
Source: https://main.vitest.dev/guide/ui
Install the Vitest UI package as a development dependency.
```bash
npm i -D @vitest/ui
```
--------------------------------
### Install Playwright Provider with bun
Source: https://main.vitest.dev/guide/browser
Install Vitest and the Playwright browser provider using bun. Recommended for CI and faster local testing.
```bash
bun add -D vitest @vitest/browser-playwright
```
--------------------------------
### Install Vitest with npm
Source: https://main.vitest.dev/guide
Install Vitest as a development dependency using npm.
```bash
npm install -D vitest
```
--------------------------------
### sequence.setupFiles Configuration
Source: https://main.vitest.dev/config/sequence
Configure the order in which setup files are executed. Options include running them in a list (sequential) or in parallel.
```APIDOC
## sequence.setupFiles
### Description
Changes the order in which setup files are executed.
* `list` will run setup files in the order they are defined
* `parallel` will run setup files in parallel
### Type
`'list' | 'parallel'`
### Default
`'parallel'`
### CLI
`--sequence.setupFiles=`
```
--------------------------------
### Install Vitest with yarn
Source: https://main.vitest.dev/guide
Install Vitest as a development dependency using yarn.
```bash
yarn add -D vitest
```
--------------------------------
### Custom Matcher Setup with Domain Adapters
Source: https://main.vitest.dev/guide/snapshot
Register custom snapshot matchers using `expect.extend` and Vitest's snapshot composables. This example shows how to set up matchers for both file-based and inline snapshots with a custom adapter.
```typescript
import { expect, Snaphsots } from 'vitest'
expect.extend({
toMatchMyDomainSnapshot(received: unknown) {
return Snaphsots.toMatchDomainSnapshot.call(this, myAdapter, received)
},
toMatchMyDomainInlineSnapshot(received: unknown, inlineSnapshot?: string) {
return Snaphsots.toMatchDomainInlineSnapshot.call(
this,
myAdapter,
received,
inlineSnapshot,
)
},
})
```
```typescript
expect(value).toMatchMyDomainSnapshot()
expect(value).toMatchMyDomainInlineSnapshot(`key=value`)
```
--------------------------------
### Configure Setup Files in Vitest
Source: https://main.vitest.dev/guide/learn/setup-teardown
Specify setup files in `vitest.config.js` to run code before every test file. This is ideal for global configurations, polyfills, or custom matchers.
```javascript
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
setupFiles: ['./test/setup.js'],
},
})
```
--------------------------------
### Install V8 Coverage Package
Source: https://main.vitest.dev/guide/coverage
Install the V8 coverage support package using npm.
```bash
npm i -D @vitest/coverage-v8
```
--------------------------------
### Comprehensive Test Tag Configuration Example
Source: https://main.vitest.dev/config/tags
An example demonstrating various tag configurations including name, description, timeout, retry, priority, and skip options. Note that `retry.condition` must be a regexp.
```typescript
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
tags: [
{
name: 'unit',
description: 'Unit tests.',
},
{
name: 'e2e',
description: 'End-to-end tests.',
timeout: 60_000,
},
{
name: 'flaky',
description: 'Flaky tests that need retries.',
retry: process.env.CI ? 3 : 0,
priority: 1,
},
{
name: 'slow',
description: 'Slow tests.',
timeout: 120_000,
},
{
name: 'skip-ci',
description: 'Tests to skip in CI.',
skip: !!process.env.CI,
},
],
},
})
```
--------------------------------
### Install WebdriverIO Provider with bun
Source: https://main.vitest.dev/guide/browser
Install Vitest and the WebdriverIO browser provider using bun. Allows running tests locally using the WebDriver protocol.
```bash
bun add -D vitest @vitest/browser-webdriverio
```
--------------------------------
### Install Playwright Provider with yarn
Source: https://main.vitest.dev/guide/browser
Install Vitest and the Playwright browser provider using yarn. Recommended for CI and faster local testing.
```bash
yarn add -D vitest @vitest/browser-playwright
```
--------------------------------
### Install Playwright Provider with pnpm
Source: https://main.vitest.dev/guide/browser
Install Vitest and the Playwright browser provider using pnpm. Recommended for CI and faster local testing.
```bash
pnpm add -D vitest @vitest/browser-playwright
```
--------------------------------
### Install OpenTelemetry Packages
Source: https://main.vitest.dev/guide/open-telemetry
Install the necessary OpenTelemetry packages for Node.js tracing. These include the SDK, auto-instrumentations, and an exporter.
```shell
npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-proto
```
--------------------------------
### Istanbul Coverage Instrumentation Example
Source: https://main.vitest.dev/guide/coverage
Illustrates how Istanbul instruments JavaScript files by adding counters for branches and functions. This is a simplified example.
```js
// Simplified example of branch and function coverage counters
const coverage = { // [!code ++]
branches: { 1: [0, 0] }, // [!code ++]
functions: { 1: 0 }, // [!code ++]
} // [!code ++]
export function getUsername(id) {
// Function coverage increased when this is invoked // [!code ++]
coverage.functions['1']++ // [!code ++]
if (id == null) {
// Branch coverage increased when this is invoked // [!code ++]
coverage.branches['1'][0]++ // [!code ++]
throw new Error('User ID is required')
}
// Implicit else coverage increased when if-statement condition not met // [!code ++]
coverage.branches['1'][1]++ // [!code ++]
return database.getUser(id)
}
globalThis.__VITEST_COVERAGE__ ||= {}
globalThis.__VITEST_COVERAGE__[filename] = coverage
```
--------------------------------
### Global Setup and Teardown Hooks
Source: https://main.vitest.dev/guide/lifecycle
Define global setup and teardown functions that run once before and after all tests. Use `project.provide` to share data with tests.
```typescript
export function setup(project) {
// Runs once before all tests
console.log('Global setup')
// Share data with tests
project.provide('apiUrl', 'http://localhost:3000')
}
export function teardown() {
// Runs once after all tests
console.log('Global teardown')
}
```
--------------------------------
### Install WebdriverIO Provider with npm
Source: https://main.vitest.dev/guide/browser
Install Vitest and the WebdriverIO browser provider using npm. Allows running tests locally using the WebDriver protocol.
```bash
npm install -D vitest @vitest/browser-webdriverio
```
--------------------------------
### Run Vitest with UI
Source: https://main.vitest.dev/guide/ui
Start Vitest with the --ui flag to launch the interactive UI.
```bash
vitest --ui
```
--------------------------------
### Install Playwright Provider with npm
Source: https://main.vitest.dev/guide/browser
Install Vitest and the Playwright browser provider using npm. Recommended for CI and faster local testing.
```bash
npm install -D vitest @vitest/browser-playwright
```
--------------------------------
### Custom Runner Example
Source: https://main.vitest.dev/api/advanced/runner
Example implementation of a custom Vitest runner class, demonstrating how to extend the base `TestRunner` and implement specific methods like `onAfterRunFiles`.
```APIDOC
## Custom Runner Example
### Description
This example shows how to create a custom runner by extending `TestRunner` and implementing the `VitestTestRunner` interface. It demonstrates initializing the `config` property and overriding lifecycle methods.
### Class
```ts
import type { RunnerTestFile, SerializedConfig, TestRunner, VitestTestRunner } from 'vitest'
class CustomRunner extends TestRunner implements VitestTestRunner {
public config: SerializedConfig
constructor(config: SerializedConfig) {
this.config = config
}
onAfterRunFiles(files: RunnerTestFile[]) {
console.log('finished running', files)
}
}
export default CustomRunner
```
### Usage
To use a custom runner, specify its path in the Vitest configuration file using the `runner` option.
```
--------------------------------
### Install Browser OpenTelemetry Packages
Source: https://main.vitest.dev/guide/open-telemetry
Install the necessary OpenTelemetry packages for browser tracing. This includes the web trace provider and an exporter.
```shell
npm i @opentelemetry/sdk-trace-web @opentelemetry/exporter-trace-otlp-proto
```
--------------------------------
### Render Hook Example
Source: https://main.vitest.dev/api/browser/react
A basic example of rendering a custom hook using `renderHook`. It asserts the initial state returned by the hook.
```jsx
import { renderHook } from 'vitest-browser-react'
test('returns logged in user', async () => {
const { result } = await renderHook(() => useLoggedInUser())
expect(result.current).toEqual({ name: 'Alice' })
})
```
--------------------------------
### Install WebdriverIO Provider with yarn
Source: https://main.vitest.dev/guide/browser
Install Vitest and the WebdriverIO browser provider using yarn. Allows running tests locally using the WebDriver protocol.
```bash
yarn add -D vitest @vitest/browser-webdriverio
```
--------------------------------
### Configure Different Browser Setups with Custom Options
Source: https://main.vitest.dev/guide/browser/multiple-setups
Define distinct configurations for browser instances, including custom setup files and injected values using the `provide` field. This allows for varied test environments within the same browser.
```typescript
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
enabled: true,
provider: playwright(),
headless: true,
instances: [
{
browser: 'chromium',
name: 'chromium-1',
setupFiles: ['./ratio-setup.ts'],
provide: {
ratio: 1,
},
},
{
browser: 'chromium',
name: 'chromium-2',
provide: {
ratio: 2,
},
},
],
},
},
})
```
```typescript
import { expect, inject, test } from 'vitest'
import { globalSetupModifier } from './example.js'
test('ratio works', () => {
expect(inject('ratio') * globalSetupModifier).toBe(14)
})
```
--------------------------------
### Install WebdriverIO Provider with pnpm
Source: https://main.vitest.dev/guide/browser
Install Vitest and the WebdriverIO browser provider using pnpm. Allows running tests locally using the WebDriver protocol.
```bash
pnpm add -D vitest @vitest/browser-webdriverio
```
--------------------------------
### Install DOM Mocking Environment
Source: https://main.vitest.dev/guide/features
Install happy-dom or jsdom to mock browser DOM and APIs. Choose the environment that best suits your project's needs.
```bash
$ npm i -D happy-dom
```
```bash
$ npm i -D jsdom
```
--------------------------------
### Conditionally Run Setup Logic with Tags
Source: https://main.vitest.dev/guide/test-tags
Use `TestRunner.matchesTags` within `beforeAll` to execute setup logic only when tests matching specific tags are included by the `--tags-filter` CLI option. This helps avoid running expensive operations unnecessarily.
```typescript
import { beforeAll, TestRunner } from 'vitest'
beforeAll(async () => {
// Seed database when "vitest --tags-filter db" is used
if (TestRunner.matchesTags(['db'])) {
await seedDatabase()
}
})
```
--------------------------------
### Extend Expect API in Setup File
Source: https://main.vitest.dev/guide/learn/setup-teardown
Import and extend Vitest's `expect` object within a setup file to add custom matchers globally for all tests.
```javascript
// This runs before every test file
import { expect } from 'vitest'
import { customMatchers } from './custom-matchers.js'
expect.extend(customMatchers)
```
--------------------------------
### Setup HTTP Request Mocking with MSW
Source: https://main.vitest.dev/guide/mocking/requests
Configure Mock Service Worker to intercept and mock HTTP GET requests. Ensure the server is started before all tests, closed after all tests, and handlers are reset after each test for isolation. Use `onUnhandledRequest: 'error'` to catch unhandled requests.
```javascript
import { afterAll, afterEach, beforeAll } from 'vitest'
import { setupServer } from 'msw/node'
import { http, HttpResponse } from 'msw'
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
]
export const restHandlers = [
http.get('https://rest-endpoint.example/path/to/posts', () => {
return HttpResponse.json(posts)
}),
]
const server = setupServer(...restHandlers)
// Start server before all tests
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
// Close server after all tests
afterAll(() => server.close())
// Reset handlers after each test for test isolation
afterEach(() => server.resetHandlers())
```
--------------------------------
### createVitest API
Source: https://main.vitest.dev/guide/advanced
Creates a Vitest instance without starting tests or validating installed packages. It returns the same `Vitest` instance as `startVitest`.
```APIDOC
## createVitest
### Description
Creates a Vitest instance. It returns the same `Vitest` instance as `startVitest`, but it does not start tests and does not validate installed packages.
### Method
`createVitest(mode: VitestRunMode, options: CliOptions, viteOverrides: ViteUserConfig = {}, vitestOptions: VitestOptions = {}): Promise`
### Parameters
- **mode** (VitestRunMode) - Required - The mode to create Vitest in (e.g., 'test').
- **options** (CliOptions) - Required - CLI arguments.
- **viteOverrides** (ViteUserConfig) - Optional - Complete Vite config, which takes precedence over other user-defined options.
- **vitestOptions** (VitestOptions) - Optional - Vitest specific options.
### Request Example
```js
import { createVitest } from 'vitest/node'
const vitest = await createVitest('test', {
watch: false,
})
```
```
--------------------------------
### Setup GraphQL Request Mocking with MSW
Source: https://main.vitest.dev/guide/mocking/requests
Configure Mock Service Worker to intercept and mock GraphQL queries. This setup includes starting the server, closing it after tests, and resetting handlers between tests. The `onUnhandledRequest: 'error'` option is used for error handling.
```javascript
import { afterAll, afterEach, beforeAll } from 'vitest'
import { setupServer } from 'msw/node'
import { graphql, HttpResponse } from 'msw'
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
]
const graphqlHandlers = [
graphql.query('ListPosts', () => {
return HttpResponse.json({
data: { posts },
})
}),
]
const server = setupServer(...graphqlHandlers)
// Start server before all tests
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
// Close server after all tests
afterAll(() => server.close())
// Reset handlers after each test for test isolation
afterEach(() => server.resetHandlers())
```
--------------------------------
### Logging Console Output During Collection
Source: https://main.vitest.dev/api/advanced/test-suite
Example showing console logs generated during test suite definition and setup phases, which are captured by the API.
```typescript
describe('suite', () => {
console.log('included') // [!code highlight]
beforeAll(() => {
console.log('included') // [!code highlight]
})
test('test', () => {
console.log('not included') // [!code error]
})
})
```
--------------------------------
### Playwright server Docker Compose configuration
Source: https://main.vitest.dev/config/browser/playwright
Example Docker Compose configuration to start a Playwright server. Ensure the image and command are correctly set for your needs.
```yaml
services:
playwright:
image: mcr.microsoft.com/playwright:v1.58.1-noble
command: /bin/sh -c "npx -y playwright@1.58.1 run-server --port 6677 --host 0.0.0.0"
init: true
ipc: host
user: pwuser
ports:
- '6677:6677'
```
--------------------------------
### Render Qwik Component with Vitest Browser
Source: https://main.vitest.dev/guide/browser
Example of rendering a Qwik component using `vitest-browser-qwik` and performing interactions.
```tsx
import { render } from 'vitest-browser-qwik'
import Greeting from './greeting'
test('greeting appears on click', async () => {
// renderSSR and renderHook are also available
const screen = render()
const button = screen.getByRole('button')
await button.click()
const greeting = screen.getByText(/hello world/iu)
await expect.element(greeting).toBeInTheDocument()
})
```
--------------------------------
### Setup userEvent Instance
Source: https://main.vitest.dev/api/browser/interactivity
Use `userEvent.setup()` to create a new instance if you need to manage keyboard state across multiple interactions. The default instance is created once.
```typescript
function setup(): UserEvent
```
--------------------------------
### User Event Setup
Source: https://main.vitest.dev/api/browser/interactivity
The `userEvent.setup()` function creates a new user event instance. This is particularly useful for maintaining keyboard state across multiple interactions, ensuring correct behavior for key presses and releases.
```APIDOC
## userEvent.setup
### Description
Creates a new user event instance. This is useful if you need to keep the state of keyboard to press and release buttons correctly.
### Method
`function setup(): UserEvent`
### Notes
- Unlike `@testing-library/user-event`, the default `userEvent` instance from `vitest/browser` is created once.
- With `playwright` and `webdriverio` providers, interactions can persist between tests. Vitest resets keyboard state automatically before each test, but pointer state is not reset.
- To ensure a neutral hover state, use `userEvent.unhover(document.body)` in a `beforeEach` hook.
```
--------------------------------
### GitHub Actions Workflow for Updating Screenshots
Source: https://main.vitest.dev/guide/browser/visual-regression-testing
This workflow is designed to be manually triggered. It runs on feature branches, prevents concurrent runs, and commits updated screenshots with co-authorship credit. It includes steps for checkout, Git configuration, Node.js setup, dependency installation, Playwright browser installation, running the visual regression test, checking for changes, committing, pushing, and generating a summary.
```yaml
name: Update Visual Regression Screenshots
on:
workflow_dispatch: # manual trigger only
env:
AUTHOR_NAME: 'github-actions[bot]'
AUTHOR_EMAIL: '41898282+github-actions[bot]@users.noreply.github.com'
COMMIT_MESSAGE: |
test: update visual regression screenshots
Co-authored-by: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
jobs:
update-screenshots:
runs-on: ubuntu-24.04
# safety first: don't run on main
if: github.ref_name != github.event.repository.default_branch
# one at a time per branch
concurrency:
group: visual-regression-screenshots@${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: write # needs to push changes
steps:
- name: Checkout selected branch
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
# use PAT if triggering other workflows
# token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git
run: |
git config --global user.name "${{ env.AUTHOR_NAME }}"
git config --global user.email "${{ env.AUTHOR_EMAIL }}"
# your setup steps here (node, pnpm, whatever)
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx --no playwright install --with-deps --only-shell
# the magic happens below đĒ
- name: Update Visual Regression Screenshots
run: npm run test:visual --update
# check what changed
- name: Check for changes
id: check_changes
run: |
CHANGED_FILES=$(git status --porcelain | awk '{print $2}')
if [ "${CHANGED_FILES:+x}" ]; then
echo "changes=true" >> $GITHUB_OUTPUT
echo "Changes detected"
# save the list for the summary
echo "changed_files<> $GITHUB_OUTPUT
echo "$CHANGED_FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "changed_count=$(echo "$CHANGED_FILES" | wc -l)" >> $GITHUB_OUTPUT
else
echo "changes=false" >> $GITHUB_OUTPUT
echo "No changes detected"
fi
# commit if there are changes
- name: Commit changes
if: steps.check_changes.outputs.changes == 'true'
run: |
git add -A
git commit -m "${{ env.COMMIT_MESSAGE }}"
- name: Push changes
if: steps.check_changes.outputs.changes == 'true'
run: git push origin ${{ github.ref_name }}
# pretty summary for humans
- name: Summary
run: |
if [[ "${{ steps.check_changes.outputs.changes }}" == "true" ]]; then
echo "### đ¸ Visual Regression Screenshots Updated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Successfully updated **${{ steps.check_changes.outputs.changed_count }}** screenshot(s) on
`${{ github.ref_name }}
`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "#### Changed Files:" >> $GITHUB_STEP_SUMMARY
echo "
```
" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.check_changes.outputs.changed_files }}" >> $GITHUB_STEP_SUMMARY
echo "
```
" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "â The updated screenshots have been committed and pushed. Your visual regression baseline is now up to date!" >> $GITHUB_STEP_SUMMARY
else
echo "### âšī¸ No Screenshot Updates Required" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The visual regression test command ran successfully but no screenshots needed updating." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "All screenshots are already up to date! đ" >> $GITHUB_STEP_SUMMARY
fi
```
--------------------------------
### start
Source: https://main.vitest.dev/api/advanced/vitest
Initializes reporters, the coverage provider, and runs tests. Accepts string filters for matching test files.
```APIDOC
## start
### Description
Initializes reporters, the coverage provider, and runs tests. This method accepts string filters to match the test files.
### Method
```ts
function start(filters?: string[]): Promise
```
### Parameters
#### Query Parameters
- **filters** (string[]) - Optional - Filters to match the test files.
```
--------------------------------
### Initialize Vitest Browser Mode with npm
Source: https://main.vitest.dev/guide/browser
Use this command to install necessary dependencies and set up browser configuration for Vitest.
```bash
npx vitest init browser
```
--------------------------------
### Initialize Vitest Browser Mode with bun
Source: https://main.vitest.dev/guide/browser
Use this command to install necessary dependencies and set up browser configuration for Vitest.
```bash
bunx vitest init browser
```
--------------------------------
### Implement Vitest Reporter with onInit and onTestRunStart
Source: https://main.vitest.dev/api/advanced/reporters
Demonstrates implementing a custom Vitest reporter by storing the Vitest instance in onInit and logging the number of test files in onTestRunStart. Requires importing necessary types from 'vitest/node'.
```typescript
import type { Reporter, TestSpecification, Vitest } from 'vitest/node'
class MyReporter implements Reporter {
private vitest!: Vitest
onInit(vitest: Vitest) {
this.vitest = vitest
}
onTestRunStart(specifications: TestSpecification[]) {
console.log(
specifications.length,
'test files will run in',
this.vitest.config.root,
)
}
}
export default new MyReporter()
```
--------------------------------
### Initialize Vitest Browser Mode with pnpm
Source: https://main.vitest.dev/guide/browser
Use this command to install necessary dependencies and set up browser configuration for Vitest.
```bash
pnpx vitest init browser
```
--------------------------------
### Initialize Vitest Browser Mode with yarn
Source: https://main.vitest.dev/guide/browser
Use this command to install necessary dependencies and set up browser configuration for Vitest.
```bash
yarn exec vitest init browser
```
--------------------------------
### Setup Chrome for WebdriverIO in CI
Source: https://main.vitest.dev/guide/browser/visual-regression-testing
This YAML snippet demonstrates setting up Chrome using the browser-actions/setup-chrome action for WebdriverIO tests in a CI environment.
```yaml
# ...the rest of the workflow
- uses: browser-actions/setup-chrome@v1
with:
chrome-version: 120
```
--------------------------------
### GitHub Actions Example for Vitest Sharding
Source: https://main.vitest.dev/guide/improving-performance
This GitHub Actions workflow demonstrates how to set up test sharding across different operating systems and shard indices. It includes steps for checking out code, setting up Node.js and pnpm, running tests with sharding, uploading artifacts, and merging reports.
```yaml
name: Tests
on:
push:
branches:
- main
jobs:
tests:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Install dependencies
run: pnpm i
- name: Run tests
run: pnpm run test --reporter=blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
VITEST_BLOB_LABEL: ${{ matrix.os }}
- name: Upload Vitest results GitHub Actions Artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: vitest-results-${{ matrix.os }}-${{ matrix.shardIndex }}
path: .vitest
include-hidden-files: true
retention-days: 1
merge-reports:
if: ${{ !cancelled() }}
needs: [tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Install dependencies
run: pnpm i
- name: Download Vitest results from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
path: .vitest
merge-multiple: true
- name: Merge reports
run: npx vitest --merge-reports
```
--------------------------------
### Rendering Marko Components with @marko/testing-library
Source: https://main.vitest.dev/guide/browser
Example of rendering a Marko component using the `@marko/testing-library` package. It shows how to pass props and assert the rendered output, including snapshot testing.
```ts
// based on @testing-library/marko API
// https://testing-library.com/docs/marko-testing-library/api
import { render, screen } from '@marko/testing-library'
import Greeting from './greeting.marko'
test('renders a message', async () => {
const { baseElement } = await render(Greeting, { name: 'Marko' })
const screen = page.elementLocator(baseElement)
await expect.element(screen.getByText(/Marko/)).toBeInTheDocument()
expect(container.firstChild).toMatchInlineSnapshot(
`
Hello, Marko!
`
)
})
```
--------------------------------
### onHookStart
Source: https://main.vitest.dev/api/advanced/reporters
This method is called when any of the specified hooks (beforeAll, afterAll, beforeEach, afterEach) have started running. The context provided indicates the type of hook and the associated test entity.
```APIDOC
## onHookStart
### Description
This method is called when any of these hooks have started running: `beforeAll`, `afterAll`, `beforeEach`, `afterEach`.
If `beforeAll` or `afterAll` are started, the `entity` will be either `TestSuite` or `TestModule`.
If `beforeEach` or `afterEach` are started, the `entity` will always be `TestCase`.
### Method
`onHookStart`
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
- **context** (ReportedHookContext) - Required - Contextual information about the hook that started.
### Request Example
```ts
function onHookStart(context: ReportedHookContext): Awaitable
```
### Response
#### Success Response (200)
Void
#### Response Example
None
```
--------------------------------
### Asynchronous Render Example
Source: https://main.vitest.dev/api/browser/react
Demonstrates the correct way to await the `render` function, which is necessary for proper Suspense handling.
```tsx
import { render } from 'vitest-browser-react'
const screen = render() // [!code --]
const screen = await render() // [!code ++]
```
--------------------------------
### Async Rejects toThrow Example
Source: https://main.vitest.dev/api/expect
Use `rejects.toThrow()` to assert that an asynchronous operation throws an error. This example demonstrates catching a rejected promise.
```typescript
test('expect rejects toThrow', async ({ expect }) => {
const promise = Promise.reject(new Error('Test'))
await expect(promise).rejects.toThrow()
})
```
--------------------------------
### Detecting Async Leaks Example
Source: https://main.vitest.dev/config/detectasyncleaks
This output shows an example of an asynchronous leak detected by Vitest, specifically a `setTimeout` that executes after the test has finished.
```sh
â¯â¯â¯â¯â¯â¯â¯â¯ Async Leaks 1 â¯â¯â¯â¯â¯â¯â¯â¯
Timeout leaking in test/checkout-screen.test.tsx
26|
27|
28|
|
29|
30|
```
--------------------------------
### Example TAP Flat Report Output
Source: https://main.vitest.dev/guide/reporters
An example of the output generated by the TAP flat reporter, showing test results in a flat TAP format.
```bash
TAP version 13
1..2
not ok 1 - __tests__/test-file-1.test.ts > first test file > 2 + 2 should equal 4 # time=11.00ms
---
error:
name: "AssertionError"
message: "expected 5 to be 4 // Object.is equality"
at: "/root-directory/__tests__/test-file-1.test.ts:20:28"
actual: "5"
expected: "4"
...
ok 2 - __tests__/test-file-1.test.ts > first test file > 4 - 2 should equal 2 # time=0.00ms
```
--------------------------------
### Basic Snapshot Test Example
Source: https://main.vitest.dev/guide/snapshot
Demonstrates a basic snapshot test for user data using `toMatchKvSnapshot`. The actual output will be saved in a snapshot file.
```typescript
import { expect, test } from 'vitest'
test('user data', () => {
const user = { name: 'Alice', score: '42' }
expect(user).toMatchKvSnapshot()
})
```
--------------------------------
### Install Playwright Browsers in CI
Source: https://main.vitest.dev/guide/browser/visual-regression-testing
This YAML snippet shows how to install Playwright browsers as a step in a GitHub Actions workflow before running visual regression tests.
```yaml
# ...the rest of the workflow
- name: Install Playwright Browsers
run: npx --no playwright install --with-deps --only-shell
```
--------------------------------
### Configure Multiple Projects with Names
Source: https://main.vitest.dev/config/name
This example demonstrates how to configure multiple projects within Vitest, each with a distinct name to differentiate them in the terminal output.
```javascript
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
projects: [
{
name: 'unit',
include: ['./test/*.unit.test.js'],
},
{
name: 'e2e',
include: ['./test/*.e2e.test.js'],
},
],
},
})
```
--------------------------------
### Vitest Config with Default and Custom Project Names
Source: https://main.vitest.dev/guide/browser/multiple-setups
Example Vitest configuration demonstrating how project names are assigned, both automatically for default browser instances and manually for custom configurations.
```typescript
export default defineConfig({
test: {
browser: {
instances: [
// name: chromium
{ browser: 'chromium' },
// name: custom
{ browser: 'firefox', name: 'custom' },
]
}
}
})
```
```typescript
export default defineConfig({
test: {
name: 'custom',
browser: {
instances: [
// name: custom (chromium)
{ browser: 'chromium' },
// name: manual
{ browser: 'firefox', name: 'manual' },
]
}
}
})
```
--------------------------------
### Example JUnit XML Report Structure
Source: https://main.vitest.dev/guide/reporters
This is an example of the XML output generated by the JUnit reporter. It shows the nested structure of test suites, test cases, and failures.
```xml
AssertionError: expected 5 to be 4 // Object.is equality
⯠__tests__/test-file-1.test.ts:20:28
```
--------------------------------
### Define a Custom Vitest Environment
Source: https://main.vitest.dev/config/environment
Export a custom environment object with name, viteEnvironment, and setup/teardown functions. The setup function can perform custom setup and return teardown logic.
```ts
import type { Environment } from 'vitest'
export default {
name: 'custom',
viteEnvironment: 'ssr',
setup() {
// custom setup
return {
teardown() {
// called after all tests with this env have been run
}
}
}
}
```
--------------------------------
### Retriable Assertion Example
Source: https://main.vitest.dev/api/browser/assertions
Use `expect.element` with `page.getBy*` locators for retriable DOM assertions. This example checks for an error banner with specific text content, retrying until the condition is met.
```typescript
import { expect, test } from 'vitest'
import { page } from 'vitest/browser'
test('error banner is rendered', async () => {
triggerError()
// This creates a locator that will try to find the element
// when any of its methods are called.
// This call by itself doesn't check the existence of the element.
const banner = page.getByRole('alert', {
name: /error/i,
})
// Vitest provides `expect.element` with built-in retry-ability
// It will repeatedly check that the element exists in the DOM and that
// the content of `element.textContent` is equal to "Error!"
// until all the conditions are met
await expect.element(banner).toHaveTextContent('Error!')
})
```
--------------------------------
### Initial ARIA Snapshot Generation
Source: https://main.vitest.dev/guide/browser/aria-snapshots
This example shows the initial HTML of a shopping cart and the ARIA snapshot generated by Vitest with the `--update` flag.
```html
Your Cart
Wireless Headphones â $79.99
```
```yaml
- heading "Your Cart" [level=1]
- list "Cart Items":
- listitem: Wireless Headphones â $79.99
- button "Checkout"
```
--------------------------------
### Get multiple elements with .elements()
Source: https://main.vitest.dev/api/browser/locators
Use `.elements()` to get an array of all DOM elements matching the locator's selector. This method never throws an error; it returns an empty array if no elements are found.
```typescript
function elements(): Element[]
```
```typescript
page.getByText('Hello World').elements() // â [HTMLElement]
```
```typescript
page.getByText('World').elements() // â [HTMLElement]
```
```typescript
page.getByText('Hello', { exact: true }).elements() // â [HTMLElement]
```
```typescript
page.getByText('Hello').elements() // â [HTMLElement, HTMLElement]
```
```typescript
page.getByText('Hello USA').elements() // â []
```
--------------------------------
### CLI: Configure Test Sequence Options
Source: https://main.vitest.dev/config/sequence
Provides an example of how to set sequence options like shuffle and seed using the Vitest CLI.
```sh
npx vitest --sequence.shuffle --sequence.seed=1000
```
--------------------------------
### Implement Vitest Reporter with onTestRunStart
Source: https://main.vitest.dev/api/advanced/reporters
Shows a basic implementation of a Vitest reporter focusing on the onTestRunStart method to log the number of test files scheduled to run. Requires importing types from 'vitest/node'.
```typescript
import type { Reporter, TestSpecification } from 'vitest/node'
class MyReporter implements Reporter {
onTestRunStart(specifications: TestSpecification[]) {
console.log(specifications.length, 'test files will run')
}
}
export default new MyReporter()
```
--------------------------------
### startVitest API
Source: https://main.vitest.dev/guide/advanced
Starts Vitest tests programmatically. It returns a Vitest instance if tests can be started. If watch mode is not enabled, Vitest will call the `close` method automatically. If watch mode is enabled and the terminal supports TTY, Vitest will register console shortcuts.
```APIDOC
## startVitest
### Description
Starts Vitest tests programmatically. Returns a `Vitest` instance if tests can be started. Automatically calls `close` if not in watch mode. Registers console shortcuts in watch mode if the terminal supports TTY.
### Method
`startVitest(mode: VitestRunMode, cliFilters: string[] = [], options: CliOptions = {}, viteOverrides?: ViteUserConfig, vitestOptions?: VitestOptions): Promise`
### Parameters
- **mode** (VitestRunMode) - Required - The mode to run Vitest in (e.g., 'test').
- **cliFilters** (string[]) - Optional - A list of filters. Vitest will run only tests whose file path contains at least one of these strings.
- **options** (CliOptions) - Optional - CLI arguments that will override any test config options.
- **viteOverrides** (ViteUserConfig) - Optional - Complete Vite config, which takes precedence over other user-defined options.
- **vitestOptions** (VitestOptions) - Optional - Vitest specific options.
### Request Example
```js
import { startVitest } from 'vitest/node'
const vitest = await startVitest('test')
await vitest.close()
```
### Response
#### Success Response (Vitest Instance)
- **state.getTestModules** (Array) - Returns an array of `TestModule` objects containing test results.
#### Response Example
```ts
import type { TestModule } from 'vitest/node'
const vitest = await startVitest('test')
console.log(vitest.state.getTestModules()) // [TestModule]
```
```