搜索

PythonReactSEOPDF
GitHub Skill

vitest

Manage JavaScript/TypeScript testing projects with Vitest (test execution, configuration, mocking, coverage, and debugging). Use when running tests, configuring environments, generating coverage, or debugging tests.

knoopx☆ 2 仓库 Stars0 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

Vitest Cheatsheet

Fast unit testing framework powered by Vite.

Contents

Setup

Package.json Scripts
{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run",
    "coverage": "vitest run --coverage"
  }
}
Config (vitest.config.ts)
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: "node", // 'jsdom', 'happy-dom'
    globals: true,       // use global test functions
    setupFiles: ["./setup.ts"],
  },
});

Running Tests

vitest run           # Run once
vitest run --coverage # With coverage
vitest --reporter=verbose  # Detailed output
vitest bench         # Run benchmarks
vitest typecheck     # Run type checking
vitest related src/file.ts  # Run tests related to file

# Watch mode / Web UI (use tmux for background)
tmux new -d -s vitest 'vitest'
tmux new -d -s vitest-ui 'vitest --ui'

BDD Test Structure

Write tests using Given-When-Then style with nested describe blocks:

import { describe, it, expect, beforeEach } from "vitest";

describe("Calculator", () => {
  describe("given two positive numbers", () => {
    const a = 5;
    const b = 3;

    describe("when adding them", () => {
      it("then the result should be their sum", () => {
        expect(a + b).toBe(8);
      });
    });

    describe("when subtracting them", () => {
      it("then the result should be the difference", () => {
        expect(a - b).toBe(2);
      });
    });
  });

  describe("given a division by zero", () => {
    describe("when dividing", () => {
      it("then it should return Infinity", () => {
        expect(1 / 0).toBe(Infinity);
      });
    });
  });
});

Assertions

expect(value).toBe(expected);
expect(value).toEqual(expected);
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toContain(item);
expect(value).toHaveLength(length);
expect(value).toThrow(error);

Async Tests (BDD Style)

import { describe, it, expect, beforeEach } from "vitest";

describe("UserAPI", () => {
  describe("given a valid user ID", () => {
    const userId = 1;

    describe("when fetching the user", () => {
      it("then the user data should be returned", async () => {
        const user = await fetchUser(userId);

        expect(user).toBeDefined();
        expect(user.id).toBe(userId);
      });
    });
  });

  describe("given an invalid user ID", () => {
    const userId = -1;

    describe("when fetching the user", () => {
      it("then it should throw a NotFoundError", async () => {
        await expect(fetchUser(userId)).rejects.toThrow("User not found");
      });
    });
  });
});

Mocking (BDD Style)

import { vi, describe, it, expect, beforeEach } from "vitest";

describe("OrderService", () => {
  describe("given a mocked payment gateway", () => {
    const mockPaymentGateway = {
      charge: vi.fn(),
    };

    beforeEach(() => {
      vi.clearAllMocks();
    });

    describe("when processing a valid order", () => {
      beforeEach(() => {
        mockPaymentGateway.charge.mockResolvedValue({ success: true });
      });

      it("then the payment should be charged", async () => {
        const orderService = new OrderService(mockPaymentGateway);
        await orderService.process({ amount: 100 });

        expect(mockPaymentGateway.charge).toHaveBeenCalledWith(100);
      });

      it("then the order should be marked as paid", async () => {
        const orderService = new OrderService(mockPaymentGateway);
        const result = await orderService.process({ amount: 100 });

        expect(result.status).toBe("paid");
      });
    });

    describe("when payment fails", () => {
      beforeEach(() => {
        mockPaymentGateway.charge.mockRejectedValue(new Error("Payment declined"));
      });

      it("then the order should be marked as failed", async () => {
        const orderService = new OrderService(mockPaymentGateway);

        await expect(orderService.process({ amount: 100 })).rejects.toThrow("Payment declined");
      });
    });
  });
});

Module Mocking (BDD Style)

import { vi, describe, it, expect, beforeEach } from "vitest";

vi.mock("./email-service", () => ({
  sendEmail: vi.fn(),
}));

import { sendEmail } from "./email-service";
import { UserService } from "./user-service";

describe("UserService", () => {
  describe("given a mocked email service", () => {
    beforeEach(() => {
      vi.clearAllMocks();
    });

    describe("when a user registers successfully", () => {
      it("then a welcome email should be sent", async () => {
        const userService = new UserService();
        await userService.register({ email: "alice@example.com", name: "Alice" });

        expect(sendEmail).toHaveBeenCalledWith(
          "alice@example.com",
          expect.stringContaining("Welcome")
        );
      });
    });

    describe("when registration fails due to invalid email", () => {
      it("then no email should be sent", async () => {
        const userService = new UserService();

        await expect(
          userService.register({ email: "invalid", name: "Bob" })
        ).rejects.toThrow();

        expect(sendEmail).not.toHaveBeenCalled();
      });
    });
  });
});

Spying (BDD Style)

import { vi, describe, it, expect, beforeEach } from "vitest";

describe("Logger", () => {
  describe("given a console spy", () => {
    let consoleSpy: ReturnType<typeof vi.spyOn>;

    beforeEach(() => {
      consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
    });

    afterEach(() => {
      consoleSpy.mockRestore();
    });

    describe("when logging a message", () => {
      it("then the message should be written to console", () => {
        const logger = new Logger();
        logger.info("Hello, World!");

        expect(consoleSpy).toHaveBeenCalledWith("[INFO]", "Hello, World!");
      });
    });
  });
});

Hooks (BDD Style)

import { describe, it, expect, beforeAll, beforeEach, afterEach, afterAll } from "vitest";

describe("Database Operations", () => {
  describe("given a database connection", () => {
    let db: Database;

    beforeAll(async () => {
      db = await Database.connect(":memory:");
    });

    afterAll(async () => {
      await db.close();
    });

    describe("given an empty users table", () => {
      beforeEach(async () => {
        await db.exec("DELETE FROM users");
      });

      describe("when inserting a user", () => {
        it("then the user count should be 1", async () => {
          await db.insert("users", { name: "Alice" });

          const count = await db.count("users");
          expect(count).toBe(1);
        });
      });

      describe("when querying users", () => {
        it("then the result should be empty", async () => {
          const users = await db.query("SELECT * FROM users");

          expect(users).toHaveLength(0);
        });
      });
    });
  });
});

Error Testing (BDD Style)

import { describe, it, expect } from "vitest";

describe("Validator", () => {
  describe("given an empty string", () => {
    const input = "";

    describe("when validating as required field", () => {
      it("then it should throw a ValidationError", () => {
        expect(() => validateRequired(input)).toThrow("Field is required");
      });

      it("then the error should be a ValidationError instance", () => {
        expect(() => validateRequired(input)).toThrow(ValidationError);
      });
    });
  });

  describe("given a valid email", () => {
    const email = "test@example.com";

    describe("when validating email format", () => {
      it("then it should not throw", () => {
        expect(() => validateEmail(email)).not.toThrow();
      });
    });
  });

  describe("given an invalid email", () => {
    const email = "not-an-email";

    describe("when validating email format", () => {
      it("then it should throw with descriptive message", () => {
        expect(() => validateEmail(email)).toThrow(/invalid email format/i);
      });
    });
  });
});

Coverage

export default defineConfig({
  test: {
    coverage: {
      reporter: ["text", "json", "html"],
      exclude: ["node_modules", "test"],
    },
  },
});

Environments

// Node.js (default)
test: { environment: "node" }

// Browser
test: { environment: "jsdom" }

// Custom
test: {
  environment: "jsdom",
  setupFiles: ["./setup.js"],
}

Configuration Options

export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: ["./test/setup.ts"],
    testTimeout: 10000,
    include: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
    exclude: ["**/node_modules/**", "**/dist/**"],
    coverage: {
      reporter: ["text", "json"],
      exclude: ["node_modules/", "src/test/"],
    },
  },
});

Projects

export default defineConfig({
  test: {
    projects: [
      {
        name: "unit",
        test: { include: ["**/*.test.ts"] },
      },
      {
        name: "integration",
        test: { include: ["**/*.spec.ts"] },
      },
    ],
  },
});

Browser Testing

export default defineConfig({
  test: {
    browser: {
      enabled: true,
      name: "chromium",
      provider: "playwright",
    },
  },
});

Benchmarking

import { bench, describe } from "vitest";

describe("Sorting Performance", () => {
  describe("given an array of 1000 numbers", () => {
    const numbers = Array.from({ length: 1000 }, () => Math.random());

    bench("when using native sort", () => {
      [...numbers].sort((a, b) => a - b);
    });

    bench("when using custom quicksort", () => {
      quicksort([...numbers]);
    });
  });
});

Type Checking

vitest typecheck              # Check types alongside tests
vitest typecheck --run        # Single run

Tips

  • Use globals: true to avoid importing test functions
  • vitest run in CI for single run
  • --coverage generates coverage reports
  • Mock external dependencies with vi.mock()
  • Use --reporter=verbose for detailed test output
  • Browser mode for real browser testing: --browser
  • Use tmux for watch mode: tmux new -d -s vitest 'vitest'
  • Use vitest bench for performance testing
  • Structure tests with Given-When-Then for clarity

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-01-20
索引更新时间
2026-01-26
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!