Install

ni -D vitest @vitest/ui jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event

Config

vite.config.ts
/// <reference types="vitest" />
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react-swc"
 
export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: "./src/tests/setup.ts",
  },
})
src/tests/setup.ts
import { afterEach } from "vitest"
import { cleanup } from "@testing-library/react"
import "@testing-library/jest-dom/vitest"
 
afterEach(() => {
  cleanup()
})
package.json
{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui"
  }
}

Example

import { describe, expect, it } from "vitest"
import { renderHook } from "@testing-library/react"
import { act } from "react-dom/test-utils"
import useCounter from "../hooks/use-counter"
 
describe("useCounter", () => {
  it("should increment", () => {
    const { result } = renderHook(() => useCounter())
    act(() => {
      result.current.inc()
    })
    expect(result.current.count).toBe(1)
  })
})
export interface RenderHookResult<Result, Props> {
  /**
   * Triggers a re-render. The props will be passed to your renderHook callback.
   */
  rerender: (props?: Props) => void
  /**
   * This is a stable reference to the latest value returned by your renderHook
   * callback
   */
  result: {
    /**
     * The value returned by your renderHook callback
     */
    current: Result
  }
  /**
   * Unmounts the test component. This is useful for when you need to test
   * any cleanup your useEffects have.
   */
  unmount: () => void
}

Thanks