T-CREATOR

Jest エラーのよくある原因と対策リスト

Jest エラーのよくある原因と対策リスト

Jest でテストを書いていると、必ずと言っていいほど様々なエラーに遭遇します。そんな時、「また分からないエラーが...」と落ち込む必要はありません。

実は、Jest のエラーには明確なパターンがあり、適切な対処法を知っていれば、短時間で解決できるものがほとんどです。この記事では、実際の開発現場でよく遭遇する Jest エラーを厳選し、その原因と具体的な解決策を詳しく解説いたします。

きっと皆さんも「このエラー見たことある!」と思うものがあるはずです。一つずつ丁寧に対処法を身につけていけば、エラー解決のスピードが格段に向上し、テスト開発がより楽しくなるでしょう。

背景

現代の JavaScript・TypeScript 開発において、Jest は欠かせないテストフレームワークとなっています。しかし、その豊富な機能と柔軟性の裏には、設定の複雑さや環境依存の問題が潜んでいます。

特に以下のような状況で、開発者は Jest エラーに悩まされることが多いです:

  • プロジェクト初期設定時:TypeScript や Next.js、React との統合で発生する設定エラー
  • テスト実行時:モジュール解決やパス設定の問題
  • CI/CD 環境:ローカルでは動作するが、本番環境で失敗するケース
  • チーム開発:メンバー間での環境差異による不具合

これらの問題は、単にエラーを解決するだけでなく、開発チーム全体の生産性にも大きな影響を与えます。だからこそ、体系的にエラー対策を学ぶことが重要なのです。

エラー診断フローチャート

初期診断のステップ

Jest エラーに遭遇したら、まず以下の順序で診断を行いましょう。焦らずに、一つずつ確認していくことが解決への近道です。

#診断項目確認内容期待される結果
1エラーメッセージの分類エラーの種類を特定環境/実行/記述のいずれか
2Jest 設定の確認jest.config.js の存在と内容適切な設定が存在
3依存関係の確認package.json の Jest 関連パッケージ必要なパッケージが全て存在
4Node.js 環境の確認バージョン互換性サポートされているバージョン

エラーメッセージの読み方

Jest のエラーメッセージは、一見複雑に見えますが、実は非常に親切に設計されています。エラーメッセージを読む際は、以下の順序で注目しましょう:

typescript// 典型的なJestエラーメッセージの構造
FAIL  src/components/Button.test.tsxTest suite failed to run

    Cannot find module '../utils/helpers' from 'src/components/Button.test.tsx'

    Require stack:
      src/components/Button.test.tsx
      node_modules/jest-runner/build/runTest.js
      node_modules/jest-runner/build/testWorker.js

このエラーメッセージから読み取れる情報:

  • FAIL: テストの実行が失敗したこと
  • ファイル名: 問題が発生したテストファイル
  • エラー種別: "Cannot find module" = モジュール解決エラー
  • 問題箇所: '../utils/helpers' というモジュールが見つからない

ログ解析のポイント

Jest のログを効果的に活用するために、以下の設定を追加することをお勧めします:

json{
  "scripts": {
    "test": "jest --verbose",
    "test:debug": "jest --verbose --no-cache --watchAll=false"
  }
}

--verboseオプションにより、各テストの詳細な実行状況が確認できます。--no-cacheは、キャッシュが原因の問題を排除するのに役立ちます。

環境構築段階のエラー

インストール・セットアップ問題

Cannot find module 'jest' エラー

最も基本的でありながら、初心者が最初に遭遇しがちなエラーです。

bashbash: jest: command not found
# または
Cannot find module 'jest'

原因:Jest がインストールされていない、またはパスが通っていない

解決策

bash# Yarnを使用してJestをインストール
yarn add --dev jest @types/jest

# TypeScriptプロジェクトの場合
yarn add --dev jest @types/jest ts-jest typescript

プロジェクトの性質に応じて、以下のような追加パッケージも必要になる場合があります:

bash# React プロジェクトの場合
yarn add --dev @testing-library/react @testing-library/jest-dom

# Next.js プロジェクトの場合
yarn add --dev @testing-library/react @testing-library/jest-dom jest-environment-jsdom

SyntaxError: Unexpected token 'export'

ES Modules を使用しているプロジェクトでよく発生するエラーです。

javascriptSyntaxError: Unexpected token 'export'
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)

原因:Jest が ES Modules の構文を理解できない

解決策:jest.config.js で適切な Transform を設定します:

javascriptmodule.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  transform: {
    '^.+\\.tsx?$': 'ts-jest',
    '^.+\\.jsx?$': 'babel-jest',
  },
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
  transformIgnorePatterns: [
    'node_modules/(?!(.*\\.mjs$|@testing-library))',
  ],
};

初回実行時のエラー

Jest encountered an unexpected token

TypeScript プロジェクトで特に多いエラーです。

bashJest encountered an unexpected token

    SyntaxError: Unexpected token '{'

原因:TypeScript ファイルが JavaScript として解釈されている

解決策:TypeScript 対応の設定を追加します:

javascript// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  // TypeScriptファイルを正しく処理するための設定
  transform: {
    '^.+\\.ts$': 'ts-jest',
    '^.+\\.tsx$': 'ts-jest',
  },
  // テストファイルの拡張子を指定
  testMatch: [
    '**/__tests__/**/*.(ts|tsx|js)',
    '**/*.(test|spec).(ts|tsx|js)',
  ],
};

設定ファイル関連

Configuration Error: Could not locate module

設定ファイルの書き方に誤りがある場合のエラーです。

bashConfiguration Error: Could not locate module 'jest-preset-angular' mapped as:
{
  "preset": "jest-preset-angular"
}

原因:指定されたプリセットやモジュールが存在しない

解決策:必要なプリセットを正しくインストールし、設定を見直します:

bash# 必要なプリセットをインストール
yarn add --dev jest-preset-angular

# または、カスタム設定を使用
javascript// jest.config.js - カスタム設定の例
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
  moduleNameMapping: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

テスト実行時のエラー

モジュール読み込みエラー

Cannot find module from 'test file'

最も頻繁に遭遇するエラーの一つです。パスの設定ミスや、モジュール解決の問題が原因です。

bashCannot find module '../utils/api' from 'src/components/UserProfile.test.tsx'

原因:相対パスの誤りまたはモジュールマッピングの設定不備

解決策:まず、実際のファイル構造を確認し、正しいパスを設定します:

javascript// jest.config.js
module.exports = {
  moduleNameMapping: {
    // @ を src ディレクトリにマッピング
    '^@/(.*)$': '<rootDir>/src/$1',
    // ~ を プロジェクトルートにマッピング
    '^~/(.*)$': '<rootDir>/$1',
  },
  // モジュール解決の順序を指定
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
};

テストファイルでは、以下のような書き方ができるようになります:

typescript// 相対パスの代わりに絶対パスを使用
import { ApiClient } from '@/utils/api';
import { UserProfile } from '@/components/UserProfile';

describe('UserProfile', () => {
  it('should render user name', () => {
    // テストコード
  });
});

Module not found: Can't resolve 'fs'

ブラウザ環境で実行されるテストで、Node.js 固有のモジュールを使用しようとした際のエラーです。

bashModule not found: Can't resolve 'fs' in '/project/src'

原因:ブラウザ環境(jsdom)で Node.js API を使用している

解決策:環境に応じた設定を行います:

javascript// jest.config.js
module.exports = {
  testEnvironment: 'node', // Node.js環境でテストを実行
  // または、テストファイルごとに環境を指定
  testMatch: {
    '**/*.node.test.js': 'node',
    '**/*.browser.test.js': 'jsdom',
  },
};

構文・型エラー

TypeScript compilation errors

TypeScript プロジェクトでよく発生する型関連のエラーです。

bashTypeScript diagnostics (customize using '[jest-config].globals.ts-jest.diagnostics' option):
Error: src/components/Button.test.tsx(10,25): error TS2339: Property 'mockImplementation' does not exist on type '() => any'.

原因:Jest 関連の型定義が不足している

解決策:適切な型定義を追加し、設定を最適化します:

typescript// src/setupTests.ts
import '@testing-library/jest-dom';

// Jest関連の型を全域で利用可能にする
declare global {
  namespace jest {
    interface Matchers<R> {
      toBeInTheDocument(): R;
      toHaveClass(className: string): R;
    }
  }
}
javascript// jest.config.js
module.exports = {
  preset: 'ts-jest',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
  globals: {
    'ts-jest': {
      tsconfig: {
        jsx: 'react-jsx',
      },
    },
  },
};

ランタイムエラー

ReferenceError: window is not defined

ブラウザ固有の API を使用している際のエラーです。

bashReferenceError: window is not defined
    at Object.<anonymous> (src/utils/storage.ts:1:1)

原因:Node.js 環境でブラウザ API を使用している

解決策:テスト環境を jsdom に変更するか、適切なポリフィルを追加します:

javascript// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
};
typescript// src/setupTests.ts
// グローバルなポリフィルを追加
global.ResizeObserver = jest
  .fn()
  .mockImplementation(() => ({
    observe: jest.fn(),
    unobserve: jest.fn(),
    disconnect: jest.fn(),
  }));

// LocalStorageのモック
const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn(),
};
global.localStorage = localStorageMock;

テスト記述時のエラー

アサーション関連

expect(...).toBeInTheDocument is not a function

Testing Library の拡張マッチャーが認識されない場合のエラーです。

bashTypeError: expect(...).toBeInTheDocument is not a function

原因:@testing-library/jest-dom が正しく設定されていない

解決策:セットアップファイルを適切に設定します:

typescript// src/setupTests.ts
import '@testing-library/jest-dom';
javascript// jest.config.js
module.exports = {
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
  testEnvironment: 'jsdom',
};

これで、以下のようなアサーションが使用可能になります:

typescriptimport { render, screen } from '@testing-library/react';
import { Button } from './Button';

describe('Button', () => {
  it('should render button text', () => {
    render(<Button>Click me</Button>);

    // 拡張マッチャーを使用
    expect(
      screen.getByText('Click me')
    ).toBeInTheDocument();
    expect(screen.getByRole('button')).toBeVisible();
  });
});

Matcher error: received value must be a mock or spy function

モック関数の使用方法に誤りがある場合のエラーです。

bashMatcher error: received value must be a mock or spy function

Received has type:  function
Received has value: [Function: mockFunction]

原因:モック関数が正しく作成されていない

解決策:jest.fn()を使用して正しくモック関数を作成します:

typescriptdescribe('API calls', () => {
  it('should call fetch with correct parameters', async () => {
    // 正しいモック関数の作成
    const mockFetch = jest.fn().mockResolvedValue({
      ok: true,
      json: async () => ({ data: 'test' }),
    });

    // globalのfetchをモック
    global.fetch = mockFetch;

    await fetchUserData(1);

    // モック関数のアサーション
    expect(mockFetch).toHaveBeenCalledWith('/api/users/1');
    expect(mockFetch).toHaveBeenCalledTimes(1);
  });
});

モック・スパイ関連

Cannot spyOn on a primitive value

プリミティブ値に対してスパイを設定しようとした際のエラーです。

bashCannot spyOn on a primitive value; undefined given

原因:存在しないプロパティや関数にスパイを設定している

解決策:スパイの対象を正しく指定します:

typescript// 間違った例
jest.spyOn(Math, 'nonExistentMethod'); // エラー

// 正しい例
describe('Math operations', () => {
  it('should use Math.random', () => {
    const randomSpy = jest
      .spyOn(Math, 'random')
      .mockReturnValue(0.5);

    const result = generateRandomNumber();

    expect(randomSpy).toHaveBeenCalled();
    expect(result).toBe(0.5);

    // スパイをリストア
    randomSpy.mockRestore();
  });
});

Mock function has already been declared

同じモック関数を重複して宣言した際のエラーです。

bashMock function has already been declared in this test file

原因:jest.mock()の重複宣言

解決策:モック宣言を整理し、適切に管理します:

typescript// モジュール全体をモック
jest.mock('../utils/api', () => ({
  fetchUserData: jest.fn(),
  fetchUserProfile: jest.fn(),
}));

// 型安全なモックの取得
const mockApi = require('../utils/api') as jest.Mocked<
  typeof import('../utils/api')
>;

describe('User service', () => {
  beforeEach(() => {
    // 各テスト前にモックをリセット
    jest.clearAllMocks();
  });

  it('should fetch user data', async () => {
    // モック関数の実装を設定
    mockApi.fetchUserData.mockResolvedValue({
      id: 1,
      name: 'John',
    });

    const result = await getUserData(1);

    expect(mockApi.fetchUserData).toHaveBeenCalledWith(1);
    expect(result).toEqual({ id: 1, name: 'John' });
  });
});

非同期処理関連

A worker process has failed to exit gracefully

非同期処理が適切に終了されない場合のエラーです。

bashA worker process has failed to exit gracefully and has been force exited. This probably means that some code in the test file is running after the test has completed.

原因:テスト終了後も実行され続ける非同期処理がある

解決策:適切なクリーンアップ処理を追加します:

typescriptdescribe('Timer tests', () => {
  let timerId: NodeJS.Timeout;

  afterEach(() => {
    // タイマーをクリア
    if (timerId) {
      clearTimeout(timerId);
    }
    // 全てのタイマーをクリア
    jest.clearAllTimers();
  });

  it('should handle async operations', async () => {
    const promise = new Promise((resolve) => {
      timerId = setTimeout(() => {
        resolve('completed');
      }, 1000);
    });

    // タイマーを進める
    jest.advanceTimersByTime(1000);

    const result = await promise;
    expect(result).toBe('completed');
  });
});

Timeout - Async callback was not invoked within timeout

非同期テストのタイムアウトエラーです。

bashTimeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout

原因:非同期処理が指定時間内に完了しない

解決策:タイムアウト値を調整するか、テストロジックを見直します:

typescriptdescribe('API tests', () => {
  // テスト全体のタイムアウトを設定
  jest.setTimeout(10000);

  it('should handle slow API calls', async () => {
    // 個別のテストにタイムアウトを設定
    const result = await fetchLargeData();
    expect(result).toBeDefined();
  }, 15000); // 15秒のタイムアウト

  it('should handle Promise rejections', async () => {
    // Promise の reject を正しく処理
    await expect(fetchInvalidData()).rejects.toThrow(
      'Invalid data'
    );
  });
});

高度なエラー対策

カスタム設定によるエラー

Invalid configuration object

複雑な設定を行う際に発生するエラーです。

bashInvalid configuration object. Jest has been initialized using a configuration object that does not match the API schema.

原因:jest.config.js の設定内容に誤りがある

解決策:設定を段階的に構築し、検証します:

javascript// jest.config.js - 段階的な設定例
const config = {
  // 基本設定
  preset: 'ts-jest',
  testEnvironment: 'jsdom',

  // モジュール解決設定
  moduleNameMapping: {
    '^@/(.*)$': '<rootDir>/src/$1',
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
  },

  // Transform設定
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
    '^.+\\.(js|jsx)$': 'babel-jest',
  },

  // セットアップファイル
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],

  // カバレッジ設定
  collectCoverageFrom: [
    'src/**/*.{ts,tsx}',
    '!src/**/*.d.ts',
    '!src/index.ts',
  ],

  // テスト対象パターン
  testMatch: [
    '<rootDir>/src/**/__tests__/**/*.{ts,tsx}',
    '<rootDir>/src/**/*.{test,spec}.{ts,tsx}',
  ],
};

module.exports = config;

プラグイン・拡張機能関連

Cannot find module 'jest-environment-jsdom'

Jest 28 以降で発生する環境関連のエラーです。

bashCannot find module 'jest-environment-jsdom'

原因:jsdom 環境が別パッケージに分離された

解決策:必要なパッケージを追加インストールします:

bashyarn add --dev jest-environment-jsdom
javascript// jest.config.js
module.exports = {
  // Jest 28以降ではjsdom環境を明示的に指定
  testEnvironment: 'jsdom',

  // 必要に応じて環境オプションを設定
  testEnvironmentOptions: {
    url: 'http://localhost:3000',
  },
};

Plugin/Preset files are not allowed to export objects

Babel の設定に関連するエラーです。

bashPlugin/Preset files are not allowed to export objects, only functions.

原因:Babel 設定の形式が不正

解決策:正しい Babel 設定を作成します:

javascript// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    ['@babel/preset-react', { runtime: 'automatic' }],
    '@babel/preset-typescript',
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-object-rest-spread',
  ],
};

パフォーマンス問題

Jest has detected the following 1 open handle

テスト実行後にリソースが適切にクリーンアップされていない場合のエラーです。

bashJest has detected the following 1 open handle potentially keeping Jest from exiting:

  ●  TCPSERVERWRAP

      12 |     const server = http.createServer();
      13 |     server.listen(3000);
      14 |     // server.close(); // これが不足している

原因:サーバーやデータベース接続などのリソースが開いたまま

解決策:適切なクリーンアップ処理を実装します:

typescriptdescribe('Server tests', () => {
  let server: any;

  beforeEach(() => {
    server = createTestServer();
  });

  afterEach(async () => {
    // サーバーを適切にクローズ
    if (server) {
      await new Promise((resolve) => {
        server.close(resolve);
      });
    }
  });

  afterAll(async () => {
    // データベース接続をクローズ
    await closeDatabase();
  });

  it('should handle requests', async () => {
    const response = await request(server).get(
      '/api/health'
    );
    expect(response.status).toBe(200);
  });
});

実践的デバッグ手法

VSCode でのデバッグ

VSCode を使用した Jest のデバッグ設定は、効率的な問題解決に欠かせません。以下の設定を.vscode​/​launch.jsonに追加しましょう:

json{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Jest Debug",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": ["--runInBand", "--no-cache"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "env": {
        "NODE_ENV": "test"
      }
    },
    {
      "name": "Jest Debug Current File",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": [
        "--runInBand",
        "--no-cache",
        "${relativeFile}"
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

このデバッグ設定により、ブレークポイントを設定してステップ実行が可能になります。

ログ出力による問題特定

効果的なログ出力により、問題の特定が容易になります:

typescriptdescribe('Complex calculation', () => {
  it('should calculate correctly', () => {
    const input = { a: 5, b: 3 };

    // デバッグ用のログ出力
    console.log('Input:', input);

    const result = complexCalculation(input);

    // 中間結果をログ出力
    console.log('Intermediate result:', result);

    expect(result.sum).toBe(8);
    expect(result.product).toBe(15);
  });
});
bash# 詳細なログ出力でテストを実行
yarn test --verbose --no-coverage

エラー再現手順の確立

確実にエラーを再現するための手順を文書化することで、チーム全体での問題解決が効率化されます:

markdown## エラー再現手順

1. **環境情報**

   - Node.js: v18.17.0
   - Jest: ^29.5.0
   - TypeScript: ^5.0.0

2. **再現手順**

   ```bash
   yarn install
   yarn test src/components/Button.test.tsx
   ```

3. **期待される結果**

   - テストが正常に完了する

4. **実際の結果**

   - Cannot find module エラーが発生

5. **追加情報**
   - ローカル環境では正常動作
   - CI 環境でのみ発生

まとめ

Jest エラーとの向き合い方について、実践的な対策を詳しく解説してまいりました。エラーに遭遇した際は、慌てずに以下のステップを踏んでください:

効率的なエラー解決のワークフロー

  1. エラーメッセージを丁寧に読む

    • 一見複雑に見えるエラーも、実は明確な情報が含まれています
    • エラーの種類を正確に把握することが解決への第一歩です
  2. 段階的に問題を切り分ける

    • 環境構築 → テスト実行 → テスト記述の順序で問題を特定
    • 複雑な問題も、小さな部分に分けて対処すれば必ず解決できます
  3. 設定を見直す

    • jest.config.js の設定は、多くの問題の根本原因となります
    • 一度正しい設定を作成すれば、同様の問題を予防できます
  4. チーム全体での知識共有

    • エラー解決の過程を文書化し、チームメンバーと共有する
    • 同じエラーで悩む時間を削減できます

心に留めておきたいポイント

エラーは成長の機会です。一つずつ丁寧に対処していくことで、Jest に対する理解が深まり、より良いテストが書けるようになります。

焦らずに、体系的に取り組むことが重要です。エラーメッセージに隠された情報を読み取り、適切な対処法を選択できるようになれば、開発効率は格段に向上します。

継続的な学習と改善を心がけましょう。Jest は継続的に進化しており、新しい機能や改善された設定方法が定期的に提供されています。

最後に、エラー解決は一人で抱え込まず、チームメンバーやコミュニティと協力して取り組むことをお勧めします。皆さんの開発体験がより良いものになることを心より願っております。

関連リンク