agentsclimarketplace

Javascript testing patterns

Skill findscripter/everything-skills/02-engineering/javascript-testing-patterns

类书式 AI Agent 技能大典 · 精选/中文化/互见成网的 500+ 开源技能,可作为 Claude Code 插件市场一键安装。A curated, cross-referenced encyclopedia of 500+ open-source agent skills.

Install
npx -y skills add findscripter/everything-skills --skill javascript-testing-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

当为 JavaScript/TypeScript 项目搭建测试体系、写单元/集成/E2E 测试或 mock 依赖时使用;用 Jest/Vitest + Testing Library 按 AAA 模式产出可执行测试、覆盖率配置与 fixture 工厂;不适用于非 JS/TS 语言或纯环境验证、专家评审替代。触发词:单元测试、Vitest/Jest、mock、覆盖率、Testing Library

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

8.1 KB, as published. Nobody here has run it

何时使用

适用场景:

  • 为新项目搭建测试基础设施(Jest 或 Vitest)。
  • 为纯函数、类、异步方法编写单元测试。
  • 为 API、Service、数据库仓储编写集成测试。
  • mock 外部依赖(fetch、第三方模块、SMTP 等)或用依赖注入解耦。
  • 测试 React/Vue 等前端组件与自定义 Hook。
  • 实践 TDD,在 CI/CD 中配置持续测试与覆盖率门槛。

不该用(负边界):

  • 任务与 JS/TS 测试无关,或涉及其他语言/工具栈(如 Python pytest、Go test)。
  • 把测试输出当作环境特定验证、上线验证或专家评审的替代品——测试不等于生产可用证明。
  • 缺少必要输入(被测代码、依赖边界、成功判据)时,应先澄清而非臆造。

步骤

  1. 选框架:Vite 项目优先 Vitest(原生快、API 与 Jest 兼容);通用 Node/TS 项目可用 Jest(ts-jest preset)。
  2. 配置覆盖率门槛与 setup 文件(见示例 config)。
  3. 按 AAA 模式(Arrange-Act-Assert)写测试,从纯函数到类、再到异步与集成逐层推进。
  4. 隔离外部依赖:模块用 vi.mock,可控对象用依赖注入 + mock,观察调用用 vi.spyOn
  5. 用 fixture 工厂(@faker-js/faker)生成一致测试数据,避免硬编码散落。
  6. 前端用 Testing Library:优先语义查询(getByRole/getByPlaceholderText),data-testid 少用。
  7. 集成测试用 supertest 打真实路由,配 beforeAll/afterAll 建表清表、beforeEach 清数据。
  8. 接入 CI:vitest --coverage,覆盖率目标 80%+。

指令

  • 明确目标、约束与必需输入后再动手。
  • 测试行为而非实现细节;覆盖错误分支与边界,而不仅是 happy path。
  • 命名要描述「测什么」;一条测试一个逻辑断言。
  • beforeEach/afterEach 做建立与清理,防止测试间污染(mock 用 vi.clearAllMocks(),spy 用 mockRestore())。
  • 慢操作(网络、定时器)一律 mock;定时器用 vi.useFakeTimers() + vi.advanceTimersByTime()

示例

Vitest 配置(覆盖率 + setup):

// vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: ['**/*.d.ts', '**/*.config.ts', '**/dist/**'],
    },
    setupFiles: ['./src/test/setup.ts'],
  },
});

Jest 覆盖率门槛(核心约束):

// jest.config.ts
coverageThreshold: {
  global: { branches: 80, functions: 80, lines: 80, statements: 80 },
}

单元测试纯函数(含异常分支):

import { describe, it, expect } from 'vitest';
import { divide } from './calculator';

describe('divide', () => {
  it('should divide two numbers', () => {
    expect(divide(10, 2)).toBe(5);
  });
  it('should throw when dividing by zero', () => {
    expect(() => divide(10, 0)).toThrow('Division by zero');
  });
});

异步 + mock fetch:

global.fetch = vi.fn();

it('should fetch user successfully', async () => {
  const mockUser = { id: '1', name: 'John' };
  (fetch as any).mockResolvedValueOnce({ ok: true, json: async () => mockUser });

  const user = await service.fetchUser('1');
  expect(user).toEqual(mockUser);
  expect(fetch).toHaveBeenCalledWith('https://api.example.com/users/1');
});

it('should throw if not ok', async () => {
  (fetch as any).mockResolvedValueOnce({ ok: false });
  await expect(service.fetchUser('999')).rejects.toThrow('User not found');
});

依赖注入 mock 仓储(比 mock 全局更可控):

beforeEach(() => {
  mockRepository = { findById: vi.fn(), create: vi.fn() };
  service = new UserService(mockRepository);
});

it('should throw if user not found', async () => {
  vi.mocked(mockRepository.findById).mockResolvedValue(null);
  await expect(service.getUser('999')).rejects.toThrow('User not found');
});

React 组件测试(Testing Library,语义查询优先):

import { render, screen, fireEvent } from '@testing-library/react';

it('should call onSubmit with form data', () => {
  const onSubmit = vi.fn();
  render(<UserForm onSubmit={onSubmit} />);
  fireEvent.change(screen.getByPlaceholderText('Name'), { target: { value: 'John' } });
  fireEvent.click(screen.getByRole('button', { name: 'Submit' }));
  expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({ name: 'John' }));
});

Hook 测试(renderHook + act):

import { renderHook, act } from '@testing-library/react';

it('should increment count', () => {
  const { result } = renderHook(() => useCounter());
  act(() => result.current.increment());
  expect(result.current.count).toBe(1);
});

API 集成测试(supertest + 数据库生命周期):

import request from 'supertest';

beforeEach(async () => { await pool.query('TRUNCATE TABLE users CASCADE'); });

it('should create a new user', async () => {
  const res = await request(app).post('/api/users').send(userData).expect(201);
  expect(res.body).not.toHaveProperty('password'); // 不泄露敏感字段
});

fixture 工厂(faker,数据一致):

import { faker } from '@faker-js/faker';

export function createUserFixture(overrides?: Partial<User>): User {
  return {
    id: faker.string.uuid(),
    name: faker.person.fullName(),
    email: faker.internet.email(),
    ...overrides,
  };
}

定时器测试:

vi.useFakeTimers();
const cb = vi.fn();
setTimeout(cb, 1000);
expect(cb).not.toHaveBeenCalled();
vi.advanceTimersByTime(1000);
expect(cb).toHaveBeenCalled();
vi.useRealTimers();

package.json 脚本:

{ "scripts": {
  "test": "vitest",
  "test:coverage": "vitest --coverage",
  "test:ui": "vitest --ui"
}}

注意事项

  • 一条测试一个逻辑断言;测行为不测实现,避免组件重构即红的脆弱测试。
  • 必清理:mock 用 vi.clearAllMocks(),spy 用 mockRestore(),集成用 afterAll 关连接(pool.end()),否则测试相互污染、句柄泄漏。
  • 异步必须 await:断言 reject 用 await expect(...).rejects.toThrow(...),漏 await 会假绿。
  • 快照测试谨慎:大快照难审、易盲目 --update;仅用于稳定、小粒度的 UI 输出。
  • data-testid 少用,优先语义查询,更贴近真实用户行为。
  • 覆盖率是下限不是目标——80% 覆盖不等于测试有效,关键是覆盖错误分支与边界。
  • 集成测试依赖真实数据库/服务,需独立测试库与隔离环境,勿连生产或共享开发库。

互见

  • 前端 E2E、组件交互可配合 Chrome DevTools/Lighthouse 类工具做端到端与性能验证。
  • CI/CD 中将 test:coverage 作为合并门禁的一环。
  • 参考文档:Vitest(vitest.dev)、Jest(jestjs.io)、Testing Library(testing-library.com)。

采编自 sickn33/antigravity-awesome-skills(MIT 许可),已按「技能大典」SCHEMA 适配重写。

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.