Vitest Cheatsheet
Comprehensive quick reference for Vitest testing framework including matchers, mocking, hooks, snapshots, configuration, and best practices for Node.js and browser testing.
Table of Contents
- Prerequisites
- Installation & Setup
- Basic Test Structure
- Matchers & Assertions
- Mocking
- Test Hooks & Lifecycle
- Snapshots
- Configuration
- Coverage
- Test Utilities
- Best Practices
- Common Pitfalls
Prerequisites
Vitest Version: This cheatsheet targets Vitest 4.0+. Some features require specific versions (noted inline).
Requirements:
- Node.js: >= v20.0.0
- Vite: >= v6.0.0
- Package Manager: pnpm, npm, yarn, or bun
# Check Node.js versionnode --version# β v20.0.0 or higher
# Check Vite version (if installed)vite --version# β v6.0.0 or higherInstallation & Setup
Initial Setup π§
# Install Vitest as dev dependencypnpm add -D vitest
# Install TypeScript types (optional)pnpm add -D @types/node
# Add test script to package.json{ "scripts": { "test": "vitest", "test:ui": "vitest --ui", "test:run": "vitest run", "test:coverage": "vitest run --coverage" }}Basic Configuration π
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { include: ["**/*.{test,spec}.{js,ts,jsx,tsx}"], exclude: ["**/node_modules/**", "**/dist/**"], environment: "node", // 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' globals: true, // Enable global test APIs },});With Existing Vite Config π
/// <reference types="vitest/config" />import { defineConfig } from "vite";
export default defineConfig({ test: { // Vitest-specific options globals: true, environment: "jsdom", },});Run Tests π
# Run tests in watch mode (default)pnpm test
# Run tests oncepnpm test:run
# Run tests with UIpnpm test:ui
# Run specific test filepnpm test src/utils.test.ts
# Run tests matching patternpnpm test --grep "user"
# Run tests in specific filepnpm test src/utils.test.tsBasic Test Structure
Test Cases π
import { describe, it, expect, test } from "vitest";
// Using 'test' (Jest-compatible)test("adds 1 + 2 to equal 3", () => { expect(1 + 2).toBe(3);});
// Using 'it' (BDD style)it("should return true", () => { expect(true).toBe(true);});
// Test with async/awaittest("fetches user data", async () => { const user = await fetchUser(1); expect(user.id).toBe(1);});Test Suites ποΈ
import { describe, it, expect } from "vitest";
describe("Math utilities", () => { it("adds two numbers", () => { expect(add(2, 3)).toBe(5); });
it("subtracts two numbers", () => { expect(subtract(5, 2)).toBe(3); });
// Nested describe blocks describe("advanced operations", () => { it("multiplies numbers", () => { expect(multiply(2, 3)).toBe(6); }); });});Skip & Only Tests βοΈ
import { describe, it, test } from "vitest";
// Skip a testtest.skip("skipped test", () => { // This test won't run});
// Run only this testtest.only("only this test runs", () => { // Only this test executes});
// Conditional skiptest.skipIf(process.env.CI)("skips in CI", () => { // Skipped when CI=true});
// Conditional runtest.runIf(process.env.DEBUG)("runs in debug", () => { // Only runs when DEBUG=true});Todo Tests π
import { test } from "vitest";
// Mark test as todo (not implemented yet)test.todo("implement user authentication");test.todo("add error handling");Concurrent Tests β‘
import { describe, test } from "vitest";
// Run tests concurrentlydescribe("API tests", () => { test.concurrent("test 1", async () => { // Runs in parallel });
test.concurrent("test 2", async () => { // Runs in parallel });});
// Concurrent test suitedescribe.concurrent("parallel suite", () => { test("test 1", () => {}); test("test 2", () => {});});Matchers & Assertions
Equality Matchers βοΈ
import { expect, test } from "vitest";
// Strict equality (===)test("strict equality", () => { expect(1).toBe(1); expect("hello").toBe("hello"); expect({}).not.toBe({}); // Different object references});
// Deep equalitytest("object equality", () => { expect({ a: 1, b: 2 }).toEqual({ a: 1, b: 2 }); expect([1, 2, 3]).toEqual([1, 2, 3]);});
// Object matching (partial)test("object matching", () => { expect({ a: 1, b: 2, c: 3 }).toMatchObject({ a: 1, b: 2 });});Truthiness Matchers β
import { expect, test } from "vitest";
test("truthiness", () => { expect(true).toBeTruthy(); expect(1).toBeTruthy(); expect("hello").toBeTruthy(); expect({}).toBeTruthy();
expect(false).toBeFalsy(); expect(0).toBeFalsy(); expect("").toBeFalsy(); expect(null).toBeFalsy(); expect(undefined).toBeFalsy();});
test("defined/undefined", () => { expect("value").toBeDefined(); expect(undefined).toBeUndefined(); expect(null).not.toBeUndefined();});Nullability Matchers π
import { expect, test } from "vitest";
test("nullable values", () => { expect(null).toBeNullable(); expect(undefined).toBeNullable(); expect("value").not.toBeNullable();});Number Matchers π’
import { expect, test } from "vitest";
test("number comparisons", () => { expect(2 + 2).toBe(4); expect(2 + 2).toBeGreaterThan(3); expect(2 + 2).toBeGreaterThanOrEqual(4); expect(2 + 2).toBeLessThan(5); expect(2 + 2).toBeLessThanOrEqual(4);
// Floating point equality expect(0.1 + 0.2).toBeCloseTo(0.3, 5);});String Matchers π
import { expect, test } from "vitest";
test("string matching", () => { expect("hello world").toMatch("world"); expect("hello world").toMatch(/world/); expect("hello").toContain("ell"); expect("hello").toHaveLength(5);});Array Matchers π
import { expect, test } from "vitest";
test("array assertions", () => { expect([1, 2, 3]).toContain(2); expect([1, 2, 3]).toHaveLength(3); expect([1, 2, 3]).toEqual([1, 2, 3]); expect([1, 2, 3]).toContainEqual(2);});Object Matchers ποΈ
import { expect, test } from "vitest";
test("object properties", () => { const user = { name: "John", age: 30, email: "john@example.com" };
expect(user).toHaveProperty("name"); expect(user).toHaveProperty("age", 30); expect(user).toHaveProperty("name", "John");});Error Matchers β οΈ
import { expect, test } from "vitest";
test("error throwing", () => { // Throw any error expect(() => { throw new Error("error message"); }).toThrow();
// Throw specific error message expect(() => { throw new Error("error message"); }).toThrow("error message");
// Throw error matching regex expect(() => { throw new Error("error message"); }).toThrow(/error/);
// Throw specific error type expect(() => { throw new TypeError("type error"); }).toThrow(TypeError);});Promise Matchers π
import { expect, test } from "vitest";
async function fetchData() { return Promise.resolve({ data: "test" });}
async function fetchError() { return Promise.reject(new Error("fetch failed"));}
test("promise resolves", async () => { await expect(fetchData()).resolves.toEqual({ data: "test" });});
test("promise rejects", async () => { await expect(fetchError()).rejects.toThrow("fetch failed");});One Of Matcher π―
import { expect, test } from "vitest";
test("value in array", () => { expect("apple").toBeOneOf(["apple", "banana", "orange"]); expect(5).toBeOneOf([1, 2, 3, 4, 5]);});Custom Matchers π οΈ
import { expect, test } from "vitest";
// Define custom matcherexpect.extend({ toBeFoo(received: string) { const pass = received === "foo"; return { message: () => `expected ${received} to be foo`, pass, }; },});
// TypeScript types for custom matcherinterface CustomMatchers<R = unknown> { toBeFoo(): R;}
declare module "vitest" { interface Assertion<T = any> extends CustomMatchers<T> {} interface AsymmetricMatchersContaining extends CustomMatchers {}}
test("custom matcher", () => { expect("foo").toBeFoo();});Mocking
Mock Functions π
import { vi, describe, it, expect } from "vitest";
// Create mock functionconst mockFn = vi.fn();
// Basic usagemockFn("arg1", "arg2");expect(mockFn).toHaveBeenCalled();expect(mockFn).toHaveBeenCalledTimes(1);expect(mockFn).toHaveBeenCalledWith("arg1", "arg2");
// Mock implementationconst mockFn2 = vi.fn((x) => x * 2);expect(mockFn2(5)).toBe(10);
// Mock return valueconst mockFn3 = vi.fn();mockFn3.mockReturnValue(42);expect(mockFn3()).toBe(42);
// Mock resolved value (async)const mockAsync = vi.fn();mockAsync.mockResolvedValue({ data: "success" });await expect(mockAsync()).resolves.toEqual({ data: "success" });
// Mock rejected valueconst mockError = vi.fn();mockError.mockRejectedValue(new Error("failed"));await expect(mockError()).rejects.toThrow("failed");Spying on Functions π
import { vi, describe, it, expect } from "vitest";
const obj = { greet: (name: string) => `Hello ${name}`, calculate: (a: number, b: number) => a + b,};
// Spy on methodconst greetSpy = vi.spyOn(obj, "greet");
obj.greet("Alice");expect(greetSpy).toHaveBeenCalledWith("Alice");expect(greetSpy).toHaveBeenCalledTimes(1);
// Mock implementationconst calcSpy = vi.spyOn(obj, "calculate").mockImplementation((a, b) => a * b);expect(obj.calculate(2, 3)).toBe(6); // Returns 6 instead of 5
// Restore originalcalcSpy.mockRestore();expect(obj.calculate(2, 3)).toBe(5); // Back to original behaviorMocking Modules π¦
import { vi, describe, it, expect } from "vitest";
// Mock entire modulevi.mock("./utils", () => ({ fetchData: vi.fn(() => Promise.resolve({ data: "mocked" })), processData: vi.fn((data) => data.toUpperCase()),}));
// Mock with original implementationvi.mock("./api", async () => { const actual = await vi.importActual("./api"); return { ...actual, fetchUser: vi.fn(), };});
// Mock module with factoryvi.mock("./logger", () => ({ default: { log: vi.fn(), error: vi.fn(), },}));Mocking Classes ποΈ
import { vi, describe, it, expect } from "vitest";
// Mock class constructorclass UserService { getUser(id: number) { return { id, name: "User" }; }}
vi.mock("./UserService", () => ({ UserService: vi.fn().mockImplementation(() => ({ getUser: vi.fn(() => ({ id: 1, name: "Mocked User" })), })),}));
// Spy on class methodconst userService = new UserService();const getUserSpy = vi.spyOn(userService, "getUser").mockReturnValue({ id: 1, name: "Spied User",});Mocking Properties π
import { vi, describe, it, expect } from "vitest";
const obj = { get value() { return "original"; },};
// Mock getterconst valueSpy = vi.spyOn(obj, "value", "get").mockReturnValue("mocked");expect(obj.value).toBe("mocked");
// Mock setterconst setterSpy = vi.spyOn(obj, "value", "set").mockImplementation(() => {});obj.value = "new value";expect(setterSpy).toHaveBeenCalled();Mock Timers β°
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
beforeEach(() => { vi.useFakeTimers();});
afterEach(() => { vi.useRealTimers();});
it("advances time", () => { const callback = vi.fn(); setTimeout(callback, 1000);
vi.advanceTimersByTime(1000); expect(callback).toHaveBeenCalled();});
it("runs all timers", () => { const callback = vi.fn(); setTimeout(callback, 1000);
vi.runAllTimers(); expect(callback).toHaveBeenCalled();});
it("advances to next timer", () => { const callback = vi.fn(); setTimeout(callback, 1000); setTimeout(callback, 2000);
vi.advanceTimersToNextTimer(); expect(callback).toHaveBeenCalledTimes(1);});Mock Date π
import { vi, describe, it, expect } from "vitest";
it("mocks date", () => { const mockDate = new Date("2024-01-01"); vi.setSystemTime(mockDate);
expect(new Date()).toEqual(mockDate);
vi.useRealTimers(); // Restore real timers});Mock Globals π
import { vi, describe, it, expect } from "vitest";
// Mock fetchglobal.fetch = vi.fn();
it("mocks fetch", async () => { vi.mocked(fetch).mockResolvedValueOnce({ ok: true, json: async () => ({ data: "test" }), } as Response);
const response = await fetch("https://api.example.com"); const data = await response.json(); expect(data).toEqual({ data: "test" });});
// Mock window objectObject.defineProperty(window, "location", { value: { href: "https://example.com", pathname: "/test", }, writable: true,});Mock Reset & Restore π
import { vi, describe, it, expect, beforeEach } from "vitest";
const mockFn = vi.fn();
beforeEach(() => { // Reset call history but keep implementation mockFn.mockReset();
// Restore original implementation (for spies) // mockFn.mockRestore()
// Clear all mocks (reset + restore) // vi.clearAllMocks()});Test Hooks & Lifecycle
beforeAll & afterAll π―
import { describe, it, expect, beforeAll, afterAll } from "vitest";
describe("Database tests", () => { let db: Database;
beforeAll(async () => { // Runs once before all tests in suite db = await connectDatabase(); await db.migrate(); });
afterAll(async () => { // Runs once after all tests in suite await db.close(); });
it("inserts data", async () => { await db.insert({ name: "Test" }); });
it("queries data", async () => { const data = await db.query("SELECT * FROM users"); expect(data).toBeDefined(); });});beforeEach & afterEach π
import { describe, it, expect, beforeEach, afterEach } from "vitest";
describe("User service", () => { let userService: UserService;
beforeEach(async () => { // Runs before each test userService = new UserService(); await userService.clear(); });
afterEach(async () => { // Runs after each test await userService.cleanup(); });
it("creates user", async () => { const user = await userService.create({ name: "John" }); expect(user.id).toBeDefined(); });
it("updates user", async () => { const user = await userService.create({ name: "Jane" }); await userService.update(user.id, { name: "Jane Doe" }); const updated = await userService.findById(user.id); expect(updated.name).toBe("Jane Doe"); });});Cleanup with Return Function π§Ή
import { beforeEach } from "vitest";
beforeEach(async () => { const db = await setupDatabase();
// Return cleanup function (runs after each test) return async () => { await db.close(); };});onTestFinished Hook π
import { test, onTestFinished } from "vitest";
test("performs query", () => { const db = connectDb();
// Register cleanup callback onTestFinished(() => { db.close(); });
db.query("SELECT * FROM users");});
// Reusable cleanup helperfunction getTestDb() { const db = connectMockedDb(); onTestFinished(() => db.close()); return db;}Snapshots
Basic Snapshots πΈ
import { expect, test } from "vitest";
test("matches snapshot", () => { const data = { foo: "bar", nested: { value: 123 } }; expect(data).toMatchSnapshot();});
// Generated snapshot file: __snapshots__/test.snap.ts// exports['matches snapshot 1'] = `// Object {// "foo": "bar",// "nested": Object {// "value": 123,// },// }// `Inline Snapshots π
import { expect, test } from "vitest";
test("inline snapshot", () => { const result = formatData({ name: "John", age: 30 }); expect(result).toMatchInlineSnapshot(` "Name: John, Age: 30" `);});File Snapshots π
import { expect, test } from "vitest";
test("file snapshot", async () => { const html = renderComponent(); await expect(html).toMatchFileSnapshot("./snapshots/component.html");});Snapshot with Hints π·οΈ
import { expect, test } from "vitest";
test("snapshot with hint", () => { const data = { version: "1.0.0" }; expect(data).toMatchSnapshot("version data");});
// Snapshot name: "snapshot with hint: version data"Partial Snapshots π―
import { expect, test } from "vitest";
test("partial snapshot", () => { const data = { id: 1, name: "John", metadata: { created: "2024-01-01" }, };
// Match only specific properties expect(data).toMatchSnapshot({ metadata: expect.any(Object), });});Error Snapshots β οΈ
import { expect, test } from "vitest";
test("error snapshot", () => { expect(() => { throw new Error("Something went wrong"); }).toThrowErrorMatchingSnapshot();});Update Snapshots π
# Update all snapshotspnpm test --update
# Update snapshots for specific filepnpm test src/utils.test.ts --updateConfiguration
Basic Config π
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { // Test file patterns include: ["**/*.{test,spec}.{js,ts,jsx,tsx}"], exclude: ["**/node_modules/**", "**/dist/**", "**/e2e/**"],
// Test environment environment: "node", // 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime'
// Global test APIs globals: true,
// Setup files setupFiles: ["./test/setup.ts"], globalSetup: ["./test/global-setup.ts"],
// Timeouts testTimeout: 5000, hookTimeout: 10000,
// Execution pool: "forks", // 'forks' | 'threads' | 'vmThreads' poolOptions: { forks: { singleFork: true, }, }, },});Environment Configuration π
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { // Different environments per test file environmentMatchGlobs: [ ["**/*.dom.test.ts", "jsdom"], ["**/*.node.test.ts", "node"], ],
// Environment options environmentOptions: { jsdom: { url: "http://localhost:3000", }, }, },});Reporters π
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { reporters: [ "default", // Conditional reporter process.env.CI ? "github-actions" : {}, // Custom reporter with options ["json", { outputFile: "./test-results.json" }], ["html", { outputDir: "./test-results" }], ], },});Test Sequencing π
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { sequence: { // Shuffle tests shuffle: false,
// Run tests concurrently concurrent: false,
// Random seed for reproducibility seed: 12345,
// Hook execution order hooks: "stack", // 'stack' | 'parallel' | 'sequence' }, },});Workspace Configuration ποΈ
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { // Multi-project workspace workspace: [ "packages/*", { test: { name: "project-a", include: ["packages/a/**/*.test.ts"], }, }, ], },});TypeScript Configuration π·
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { globals: true, typecheck: { enabled: true, tsconfig: "./tsconfig.test.json", }, },});Coverage
Setup Coverage π
# Install coverage providerpnpm add -D @vitest/coverage-v8# orpnpm add -D @vitest/coverage-istanbulCoverage Configuration βοΈ
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { coverage: { // Coverage provider provider: "v8", // 'v8' | 'istanbul' | 'custom'
// Enable coverage enabled: true,
// Coverage reporters reporter: ["text", "json", "html", "lcov"],
// Output directory reportsDirectory: "./coverage",
// Files to include/exclude include: ["src/**/*.{ts,tsx}"], exclude: [ "**/*.test.ts", "**/*.spec.ts", "**/node_modules/**", "**/dist/**", ],
// Coverage thresholds thresholds: { lines: 80, functions: 80, branches: 80, statements: 80, },
// Per-file thresholds perFile: true,
// 100% coverage required all: true, }, },});Run Coverage π
# Run tests with coveragepnpm test --coverage
# Run coverage oncepnpm test:run --coverage
# Update coverage thresholdspnpm test --coverage --coverage.thresholds.lines=90Custom Coverage Provider π οΈ
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { coverage: { provider: "custom", customProviderModule: "./custom-coverage-provider.ts", }, },});Test Utilities
Test Context π―
import { test } from "vitest";
test("with context", ({ expect, task, onTestFinished }) => { // Access test utilities from context expect(1 + 1).toBe(2);
// Test metadata console.log(task.name); // Test name console.log(task.file); // Test file path
// Cleanup hook onTestFinished(() => { console.log("Test finished"); });});Extended Test Context π§
import { test as baseTest } from "vitest";
// Define custom fixturesconst test = baseTest.extend<{ db: Database; user: User;}>({ db: async ({}, use) => { const db = await setupDatabase(); await use(db); await db.close(); }, user: async ({ db }, use) => { const user = await db.createUser({ name: "Test User" }); await use(user); await db.deleteUser(user.id); },});
// Use extended testtest("user operations", async ({ db, user }) => { const found = await db.findUser(user.id); expect(found).toEqual(user);});Test Retry π
import { test } from "vitest";
// Retry flaky teststest( "flaky test", async () => { // Test that might fail occasionally }, { retry: 3 },);Test Timeout β±οΈ
import { test } from "vitest";
// Custom timeout per testtest( "slow test", async () => { // Long-running test }, { timeout: 10000 },);Test Repeat π
import { test } from "vitest";
// Repeat test multiple timestest( "repeat test", () => { // Test logic }, { repeats: 5 },);Best Practices
β Doβs
β Use descriptive test names
// Goodtest("returns user by id when user exists", () => {});
// Badtest("test user", () => {});β Keep tests isolated
// Each test should be independenttest("test 1", () => { const result = calculate(2, 3); expect(result).toBe(5);});
test("test 2", () => { // Doesn't depend on test 1 const result = calculate(4, 5); expect(result).toBe(9);});β Use beforeEach for common setup
describe("UserService", () => { let userService: UserService;
beforeEach(() => { userService = new UserService(); });
test("creates user", () => { const user = userService.create({ name: "John" }); expect(user).toBeDefined(); });});β Mock external dependencies
vi.mock("./api", () => ({ fetchUser: vi.fn(),}));
test("uses mocked API", async () => { vi.mocked(fetchUser).mockResolvedValue({ id: 1 }); // Test logic});β Use appropriate matchers
// Use toEqual for objects/arraysexpect({ a: 1 }).toEqual({ a: 1 });
// Use toBe for primitivesexpect(1).toBe(1);β Clean up after tests
afterEach(() => { vi.clearAllMocks(); vi.restoreAllMocks();});β Donβts
β Donβt test implementation details
// Bad - testing internal statetest("increments counter", () => { const counter = new Counter(); counter.increment(); expect(counter._count).toBe(1); // Private property});
// Good - testing behaviortest("increments counter", () => { const counter = new Counter(); counter.increment(); expect(counter.getValue()).toBe(1);});β Donβt share mutable state
// Badlet sharedData: any;
test("test 1", () => { sharedData = { value: 1 };});
test("test 2", () => { expect(sharedData.value).toBe(1); // Depends on test 1});
// Goodtest("test 1", () => { const data = { value: 1 }; expect(data.value).toBe(1);});β Donβt use magic numbers
// Badexpect(result).toBe(42);
// Goodconst EXPECTED_RESULT = 42;expect(result).toBe(EXPECTED_RESULT);β Donβt ignore errors
// Badtest("handles error", () => { try { riskyOperation(); } catch (e) { // Ignored }});
// Goodtest("handles error", () => { expect(() => riskyOperation()).toThrow();});β Donβt test multiple things in one test
// Badtest("user operations", () => { const user = createUser(); updateUser(user.id); deleteUser(user.id); expect(getUser(user.id)).toBeUndefined();});
// Good - split into multiple teststest("creates user", () => {});test("updates user", () => {});test("deletes user", () => {});Common Pitfalls
β οΈ Mocking Internal Calls
Warning: Methods called internally within the same file cannot be mocked from outside.
export function foo() { return "foo";}
export function foobar() { return `${foo()}bar`; // Internal call}
// test.ts// β This won't affect the internal foo() callvi.spyOn(mod, "foo").mockReturnValue("mocked");
// β
Mock the entire module insteadvi.mock("./utils", () => ({ foo: vi.fn(() => "mocked"), foobar: vi.fn(() => "mockedbar"),}));β οΈ Async Test Cleanup
// β Missing awaittest("async test", async () => { const result = await fetchData(); expect(result).toBeDefined(); // Cleanup might not complete cleanup();});
// β
Proper async cleanuptest("async test", async () => { const result = await fetchData(); expect(result).toBeDefined(); await cleanup();});β οΈ Timer Mocking
// β Forgetting to restore timerstest("timer test", () => { vi.useFakeTimers(); // Test logic // Timers not restored!});
// β
Always restore timerstest("timer test", () => { vi.useFakeTimers(); try { // Test logic } finally { vi.useRealTimers(); }});
// β
Or use beforeEach/afterEachbeforeEach(() => { vi.useFakeTimers();});
afterEach(() => { vi.useRealTimers();});β οΈ Concurrent Test State
// β Shared mutable state in concurrent testslet counter = 0;
test.concurrent("test 1", () => { counter++; expect(counter).toBe(1); // Might fail!});
test.concurrent("test 2", () => { counter++; expect(counter).toBe(1); // Might fail!});
// β
Use test context or fixturestest.concurrent("test 1", ({ task }) => { const counter = 0; counter++; expect(counter).toBe(1);});β οΈ Snapshot Updates
Warning: Always review snapshot changes before committing. Snapshots can hide bugs if updated blindly.
# β Blindly updating snapshotspnpm test --update
# β
Review changes firstpnpm test# Review failed snapshots# Then update if correctpnpm test --updateβ οΈ Global Mocks
// β Global mock affecting all testsvi.mock("./api"); // Affects all test files
// β
Use vi.doMock for dynamic mockingtest("specific test", async () => { vi.doMock("./api", () => ({ fetchData: vi.fn(), })); // Test logic vi.doUnmock("./api");});