Skip to content

Jest環境でAxios使用時に発生する Cannot use import statement outside a module エラー解決方法

問題の説明

Vue.jsアプリケーションでAxiosを使用するテストを実行中に、次のエラーが発生するケースがあります:

SyntaxError: Cannot use import statement outside a module

この問題は通常、以下の状況で発生します:

  • Axios 1.x以降を使用している
  • Jestでテストを実行している
  • テストファイル内でimport axios from "axios"を使用している
  • GitHub ActionsなどのCI環境で発生することが多い

問題の背景

Axios 1.0.0以降、パッケージはECMAScript Modules(ESM) 形式でリリースされるようになりました。
JestはNode.js環境で動作するため、ESMではなくCommonJS形式を期待します。

発生原因と解決方針

このエラーの根本原因は:

  1. AxiosがデフォルトでESMモジュールを提供するようになった
  2. Jestがnode_modules内のコードをデフォルトで変換しない
  3. ESM形式のコードをCommonJS環境で実行しようとしている

解決には主に2つのアプローチがあります:

  1. JestにAxiosの変換を許可(推奨)
    • transformIgnorePatternsで除外パターンを指定
  2. CommonJSビルドを明示的に使用
    • moduleNameMapperでCJSバージョンを指定

解決方法

方法1: transformIgnorePatternsを使用(推奨)

最も確実な解決策は、JestにAxiosを変換対象に含めることです。

設定例(jest.config.js):

js
module.exports = {
  transformIgnorePatterns: [
    "node_modules/(?!axios)"
  ]
}

設定例(package.json):

json
{
  "jest": {
    "transformIgnorePatterns": ["node_modules/(?!axios)"]
  }
}

設定例(Reactプロジェクトのpackage.json scripts):

json
{
  "scripts": {
    "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\""
  }
}

設定の解説

  • node_modules/(?!axios): axios以外のnode_modulesを無視
  • ?!(axios): "axios"を除外する(否定先読み)
  • この設定でJestはAxiosモジュールをトランスパイル対象に含める

方法2: moduleNameMapperでCommonJSビルドを指定

Axiosが提供するCommonJSビルドを明示的に使用する方法:

js
module.exports = {
  moduleNameMapper: {
    "axios": "axios/dist/node/axios.cjs"
  }
}

またはpackage.jsonの場合:

json
{
  "jest": {
    "moduleNameMapper": {
      "^axios$": "axios/dist/node/axios.cjs"
    }
  }
}

注意点

この方法はaxios-mock-adapterなどの関連ライブラリを使用している場合に互換性問題が発生する可能性があります。問題が発生する場合は方法1をお試しください。

その他の注意点と補足

Jestのキャッシュクリア

設定変更後にエラーが継続する場合は、キャッシュをクリア:

bash
npm test -- --clearCache

TypeScript環境での設定例

ts-jestを使用する場合の設定例:

typescript
import type { JestConfigWithTsJest } from 'ts-jest';

const config: JestConfigWithTsJest = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  moduleNameMapper: {
    '^axios$': 'axios/dist/node/axios.cjs'
  }
};

export default config;

複数ライブラリを対象にする場合

複数のESMライブラリを使用する場合の設定例:

js
const esModules = ['axios', 'another-library'].join('|');

module.exports = {
  transformIgnorePatterns: [`node_modules/(?!(${esModules}))`]
};
動作原理について(技術的背景)
  • Jestのデフォルト動作: node_modules内のモジュールは無視
  • transformIgnorePatterns: 無視リストから特定モジュールを除外
  • Axios互換モード切替: CJSビルドにはaxios.cjs形式が提供される
  • Babel連携: ESM→CJS変換はBabelが自動処理

推奨ソリューションの比較

方法メリットデメリット推奨度
transformIgnorePatterns他のライブラリにも適用可能設定が複雑な場合あり★★★★★
moduleNameMapper特定ビルドを直接指定互換性問題の可能性★★★☆☆
テストスクリプト変更即時対応可能プロジェクト全体に適用されない★★☆☆☆

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

  1. まずtransformIgnorePatternsのアプローチを試す
  2. 互換性問題が発生した場合はmoduleNameMapperの使用を検討
  3. キャッシュ問題が発生したらnpm test -- --clearCacheを実行

回避策と代替手段

Axiosバージョンを固定(緊急回避用)

一時的な回避策としてpackage.jsonで0.x系を指定:

json
{
  "axios": "0.27.2"
}

fetch APIへの置き換え

小規模プロジェクトならブラウザ標準APIへの置き換えも選択肢:

js
try {
  const response = await fetch("api/data", { method: "GET" });
  const data = await response.json();
  return data;
} catch (error) {
  handleError(error);
}

注意点

  • Axios固有の機能(インターセプタ等)が使用不可
  • 機能縮小となるため、あくまで一時的解決策

結論

JestとAxiosのインポート問題は最新のモジュールシステムの差異が主原因です。以下の手順で解決できます:

  1. Jest設定ファイル(jest.config.js)を開く
  2. transformIgnorePatterns"node_modules/(?!axios)"を追加
  3. テスト実行npm test
  4. 問題が解決しない場合はキャッシュクリアnpm test -- --clearCache

これらの設定はAxiosに限らず、JestでESMモジュールを使用する際の基本パターンとして応用できます。