mcpField
J
jest-testing

jest-testing

github.com/pluginagentmarketplaceテスト・品質2120 回インストール43 週間前に更新
リポジトリ

jest-testing について

jest-testingは、JestでNode.jsアプリケーションをテストする開発者向けのスキルです。テスト作成、モック、APIテスト、カバレッジから、統合テストやCI/CDまで扱います。

主な機能

  1. 01ユニットテストと非同期テストの作成
  2. 02モジュールや関数のモック
  3. 03SupertestによるAPIテスト
  4. 04コードカバレッジレポートの生成
  5. 05テストライフサイクルフックの設定

活用シーン

  1. 01Node.js関数のテスト作成
  2. 02APIエンドポイントの動作確認
  3. 03外部依存をモックしてテストを分離
  4. 04CI/CDパイプラインでのテスト実行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pluginagentmarketplace/custom-plugin-nodejs --skill jest-testing

インストール後、Claude Code で/jest-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
config.yaml
references/
GUIDE.md
scripts/
helper.py

詳細

Jest テストスキル

快適な JavaScript テストフレームワークである Jest を使って、Node.js アプリケーションのテストを習得しましょう。

クイックスタート

3 つのステップでテストします:

  1. インストール - npm install --save-dev jest supertest
  2. テストを作成 - *.test.js ファイルを作成します
  3. 実行 - npm test

コアコンセプト

基本的なテスト構造
// sum.test.js
const sum = require('./sum');

describe('sum function', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
  });

  test('adds negative numbers', () => {
    expect(sum(-1, -2)).toBe(-3);
  });
});
Jest の設定
// package.json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  },
  "jest": {
    "testEnvironment": "node",
    "coverageThreshold": {
      "global": {
        "branches": 80,
        "functions": 80,
        "lines": 80
      }
    }
  }
}
単体テスト
// userService.test.js
const UserService = require('./userService');
const User = require('./models/User');

jest.mock('./models/User');

describe('UserService', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('createUser', () => {
    it('should create user successfully', async () => {
      const userData = {
        name: 'John',
        email: '[email protected]'
      };

      User.create.mockResolvedValue({ id: 1, ...userData });

      const result = await UserService.createUser(userData);

      expect(User.create).toHaveBeenCalledWith(userData);
      expect(result.id).toBe(1);
    });

    it('should throw error for duplicate email', async () => {
      User.create.mockRejectedValue(new Error('Email exists'));

      await expect(UserService.createUser({}))
        .rejects
        .toThrow('Email exists');
    });
  });
});

学習ロードマップ

初級(1~2 週間)
  • ✅ Jest をセットアップし、基本的なテストを作成する
  • ✅ テスト構造(describe/it/expect)を理解する
  • ✅ マッチャー(toBe、toEqual など)を学ぶ
  • ✅ 同期関数をテストする
中級(3~4 週間)
  • ✅ 非同期関数をテストする
  • ✅ モジュールと関数をモックする
  • ✅ Supertest で API をテストする
  • ✅ コードカバレッジレポートを作成する
上級(5~6 週間)
  • ✅ 統合テスト
  • ✅ データベース操作のテスト
  • ✅ CI/CD との統合
  • ✅ パフォーマンステスト

Supertest での API テスト

const request = require('supertest');
const app = require('./app');

describe('User API', () => {
  describe('POST /api/users', () => {
    it('should create new user', async () => {
      const userData = {
        name: 'John',
        email: '[email protected]',
        password: 'password123'
      };

      const response = await request(app)
        .post('/api/users')
        .send(userData)
        .expect('Content-Type', /json/)
        .expect(201);

      expect(response.body).toHaveProperty('id');
      expect(response.body.email).toBe(userData.email);
    });

    it('should return 400 for invalid email', async () => {
      const response = await request(app)
        .post('/api/users')
        .send({ email: 'invalid' })
        .expect(400);

      expect(response.body).toHaveProperty('error');
    });
  });

  describe('GET /api/users/:id', () => {
    it('should return user by id', async () => {
      const response = await request(app)
        .get('/api/users/123')
        .expect(200);

      expect(response.body.id).toBe('123');
    });

    it('should return 404 for non-existent user', async () => {
      await request(app)
        .get('/api/users/999')
        .expect(404);
    });
  });
});

モックのパターン

// Mock entire module
jest.mock('axios');
const axios = require('axios');

test('fetches data from API', async () => {
  axios.get.mockResolvedValue({ data: { id: 1 } });

  const result = await fetchUser(1);

  expect(axios.get).toHaveBeenCalledWith('/api/users/1');
  expect(result.id).toBe(1);
});

// Spy on function
test('calls callback', () => {
  const callback = jest.fn();

  processData('test', callback);

  expect(callback).toHaveBeenCalledWith('test');
  expect(callback).toHaveBeenCalledTimes(1);
});

// Mock timers
jest.useFakeTimers();

test('delays execution', () => {
  const callback = jest.fn();

  setTimeout(callback, 1000);
  jest.advanceTimersByTime(1000);

  expect(callback).toHaveBeenCalled();
});

テストのライフサイクルフック

describe('User Tests', () => {
  beforeAll(async () => {
    // Setup test database
    await connectTestDB();
  });

  afterAll(async () => {
    // Cleanup
    await disconnectTestDB();
  });

  beforeEach(async () => {
    // Clear data before each test
    await User.deleteMany({});
  });

  afterEach(() => {
    // Cleanup after each test
    jest.clearAllMocks();
  });

  test('...', () => {});
});

Jest マッチャー

// Equality
expect(value).toBe(expected)        // Strict equality (===)
expect(value).toEqual(expected)     // Deep equality
expect(value).not.toBe(expected)    // Negation

// Truthiness
expect(value).toBeDefined()
expect(value).toBeNull()
expect(value).toBeTruthy()
expect(value).toBeFalsy()

// Numbers
expect(value).toBeGreaterThan(3)
expect(value).toBeGreaterThanOrEqual(3)
expect(value).toBeLessThan(5)
expect(value).toBeCloseTo(0.3)      // Floating point

// Strings
expect(string).toMatch(/pattern/)
expect(string).toContain('substring')

// Arrays
expect(array).toContain(item)
expect(array).toHaveLength(3)

// Objects
expect(obj).toHaveProperty('key')
expect(obj).toMatchObject({ key: 'value' })

// Exceptions
expect(() => fn()).toThrow()
expect(() => fn()).toThrow('error message')

// Async
await expect(promise).resolves.toBe(value)
await expect(promise).rejects.toThrow()

コードカバレッジ

# Run with coverage
npm test -- --coverage

# Coverage report shows:
# - Statements: % of code executed
# - Branches: % of if/else paths
# - Functions: % of functions called
# - Lines: % of lines executed

テストのベストプラクティス

  • ✅ AAA パターン:Arrange、Act、Assert
  • ✅ テストごとにアサーションを 1 つにする(理想的には)
  • ✅ 内容がわかるテスト名を付ける
  • ✅ エッジケースをテストする
  • ✅ 外部依存関係をモックする
  • ✅ テスト後にクリーンアップする
  • ✅ テスト間の依存を避ける
  • ✅ カバレッジ 80% 以上を目指す

CI/CD との統合

# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npm test -- --coverage
      - uses: codecov/codecov-action@v3

使用する場面

次の場合に Jest でテストします:

  • Node.js アプリケーションを構築する場合
  • 包括的なテストカバレッジが必要な場合
  • 高速な並列テスト実行を求める場合
  • モックとスナップショットテストが必要な場合
  • CI/CD パイプラインを実装する場合

関連スキル

  • Express REST API(API エンドポイントのテスト)
  • 非同期プログラミング(非同期コードのテスト)
  • データベース統合(DB 操作のテスト)
  • JWT 認証(認証フローのテスト)

リソース

コメント