npx skills add https://github.com/doanchienthangdev/omgkit --skill 'Testing with Vitest'// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./tests/setup.ts"],
coverage: {
provider: "v8",
reporter: ["text", "html"],
thresholds: { global: { branches: 80, functions: 80, lines: 80 } },
},
},
});
// tests/setup.ts
import { afterEach, vi } from "vitest";
import { cleanup } from "@testing-library/vue";
import "@testing-library/jest-dom/vitest";
afterEach(() => { vi.clearAllMocks(); cleanup(); });
| 功能 | 描述 | 参考链接 |
|---|---|---|
| 单元测试 | 使用 describe/it/expect 进行快速隔离测试 | Vitest API |
| 模拟 | 使用 vi 模拟模块、函数和计时器 | 模拟指南 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 快照测试 |
| 组件和数据结构快照 |
| 快照测试 |
| 组件测试 | 使用 Testing Library 进行 Vue/React 组件测试 | Vue 测试工具 |
| 覆盖率报告 | 带阈值的 V8/Istanbul 覆盖率 | 覆盖率 |
| 并行执行 | 多线程测试运行器 | 测试运行器 |
import { describe, it, expect, test } from "vitest";
describe("字符串工具", () => {
test.each([
["hello", 3, "hel..."],
["hi", 10, "hi"],
["test", 4, "test"],
])('truncate("%s", %d) 返回 "%s"', (str, len, expected) => {
expect(truncate(str, len)).toBe(expected);
});
});
import { describe, it, expect, vi, beforeEach, Mock } from "vitest";
import { UserService } from "@/services/user";
import { apiClient } from "@/lib/api";
vi.mock("@/lib/api", () => ({
apiClient: { get: vi.fn(), post: vi.fn() },
}));
describe("用户服务", () => {
beforeEach(() => vi.clearAllMocks());
it("从 API 获取用户", async () => {
const mockUser = { id: "1", name: "John" };
(apiClient.get as Mock).mockResolvedValue({ data: mockUser });
const user = await new UserService().getUser("1");
expect(apiClient.get).toHaveBeenCalledWith("/users/1");
expect(user).toEqual(mockUser);
});
});
import { describe, it, expect, vi } from "vitest";
import { mount } from "@vue/test-utils";
import Button from "@/components/Button.vue";
describe("按钮组件", () => {
it("触发点击事件", async () => {
const wrapper = mount(Button, { slots: { default: "点击" } });
await wrapper.trigger("click");
expect(wrapper.emitted("click")).toHaveLength(1);
});
it("加载时禁用", () => {
const wrapper = mount(Button, { props: { loading: true } });
expect(wrapper.attributes("disabled")).toBeDefined();
});
});
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
describe("防抖函数", () => {
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
it("延迟函数执行", () => {
const fn = vi.fn();
const debouncedFn = debounce(fn, 100);
debouncedFn();
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(100);
expect(fn).toHaveBeenCalledTimes(1);
});
});
| 建议做法 | 避免做法 |
|---|---|
| 使用描述性测试名称解释行为 | 测试实现细节 |
| 测试行为,而非内部状态 | 在测试间共享状态 |
| 使用 test.each 处理多个相似案例 | 使用任意超时 |
| 模拟外部依赖 | 过度模拟内部模块 |
| 保持测试专注且隔离 | 重复测试覆盖范围 |
| 与代码同步编写测试 | 忽略不稳定的测试 |
每周安装量
0
代码仓库
GitHub 星标数
3
首次出现
1970年1月1日
安全审计
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./tests/setup.ts"],
coverage: {
provider: "v8",
reporter: ["text", "html"],
thresholds: { global: { branches: 80, functions: 80, lines: 80 } },
},
},
});
// tests/setup.ts
import { afterEach, vi } from "vitest";
import { cleanup } from "@testing-library/vue";
import "@testing-library/jest-dom/vitest";
afterEach(() => { vi.clearAllMocks(); cleanup(); });
| Feature | Description | Reference |
|---|---|---|
| Unit Testing | Fast isolated tests with describe/it/expect | Vitest API |
| Mocking | Module, function, and timer mocking with vi | Mocking Guide |
| Snapshot Testing | Component and data structure snapshots | Snapshot Testing |
| Component Testing | Vue/React component testing with Testing Library | Vue Test Utils |
| Coverage Reports | V8/Istanbul coverage with thresholds | Coverage |
| Parallel Execution | Multi-threaded test runner | Test Runner |
import { describe, it, expect, test } from "vitest";
describe("String Utils", () => {
test.each([
["hello", 3, "hel..."],
["hi", 10, "hi"],
["test", 4, "test"],
])('truncate("%s", %d) returns "%s"', (str, len, expected) => {
expect(truncate(str, len)).toBe(expected);
});
});
import { describe, it, expect, vi, beforeEach, Mock } from "vitest";
import { UserService } from "@/services/user";
import { apiClient } from "@/lib/api";
vi.mock("@/lib/api", () => ({
apiClient: { get: vi.fn(), post: vi.fn() },
}));
describe("UserService", () => {
beforeEach(() => vi.clearAllMocks());
it("fetches user from API", async () => {
const mockUser = { id: "1", name: "John" };
(apiClient.get as Mock).mockResolvedValue({ data: mockUser });
const user = await new UserService().getUser("1");
expect(apiClient.get).toHaveBeenCalledWith("/users/1");
expect(user).toEqual(mockUser);
});
});
import { describe, it, expect, vi } from "vitest";
import { mount } from "@vue/test-utils";
import Button from "@/components/Button.vue";
describe("Button", () => {
it("emits click event", async () => {
const wrapper = mount(Button, { slots: { default: "Click" } });
await wrapper.trigger("click");
expect(wrapper.emitted("click")).toHaveLength(1);
});
it("is disabled when loading", () => {
const wrapper = mount(Button, { props: { loading: true } });
expect(wrapper.attributes("disabled")).toBeDefined();
});
});
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
describe("Debounce", () => {
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
it("delays function execution", () => {
const fn = vi.fn();
const debouncedFn = debounce(fn, 100);
debouncedFn();
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(100);
expect(fn).toHaveBeenCalledTimes(1);
});
});
| Do | Avoid |
|---|---|
| Use descriptive test names explaining behavior | Testing implementation details |
| Test behavior, not internal state | Sharing state between tests |
| Use test.each for multiple similar cases | Using arbitrary timeouts |
| Mock external dependencies | Over-mocking internal modules |
| Keep tests focused and isolated | Duplicating test coverage |
| Write tests alongside code | Ignoring flaky tests |
Weekly Installs
0
Repository
GitHub Stars
3
First Seen
Jan 1, 1970
Security Audits
Vue 3 调试指南:解决响应式、计算属性与监听器常见错误
11,400 周安装