【React/TypeScript/Jest】単体テストで遭遇する「Cannot find module 'react-dom/client'」エラー:解決策と回避策

2024-05-21

React、TypeScript、単体テストにおける「Cannot find module 'react-dom/client' from 'node_modules/@testing-library/react/dist/pure.js'」エラーの解決策

React と react-testing-library のバージョン不一致

React v17 以降では、react-dom パッケージが react-dom/clientreact-dom/server に分割されました。一方、react-testing-library v13 までは古い react-dom パッケージのみをサポートしていました。そのため、React v17 以降で react-testing-library v13 を使用すると、このエラーが発生します。

解決策

    • React v16 以下を使用している場合は、react-testing-library v12 以下を使用する必要があります。

    TypeScript 環境における型宣言ファイル不足

    TypeScript を使用している場合、react-dom/client パッケージの型宣言ファイルがインストールされていないことが原因で、このエラーが発生することがあります。

    以下のコマンドを実行して、@types/react-dom パッケージをインストールします。

    npm install --save-dev @types/react-dom
    

    補足

    このエラー以外にも、Jest の設定やその他の環境要因によって発生する可能性があります。問題解決にあたっては、以下の情報源も参考にしてみてください。

      上記の情報で解決しない場合は、具体的なプロジェクト構成やエラーメッセージなどを共有していただければ、より詳細なアドバイスを提供できる可能性があります。




      // react-testing-library v13 以下での例
      
      import React from 'react';
      import { render, screen } from '@testing-library/react';
      import MyComponent from './MyComponent';
      
      test('MyComponent renders correctly', () => {
        render(<MyComponent />);
      
        const textElement = screen.getByText('Hello, World!');
        expect(textElement).toBeInTheDocument();
      });
      
      // react-testing-library v14 以降での例
      
      import React from 'react';
      import { render, screen } from '@testing-library/react';
      import MyComponent from './MyComponent';
      
      test('MyComponent renders correctly', () => {
        render(<MyComponent />);
      
        const textElement = screen.getByText('Hello, World!');
        expect(textElement).toBeInTheDocument();
      });
      
      // react-testing-library v13 以下での例
      
      import React from 'react';
      import { render, screen } from '@testing-library/react';
      import MyComponent from './MyComponent';
      
      test('MyComponent renders correctly', () => {
        render(<MyComponent />);
      
        const textElement: HTMLElement = screen.getByText('Hello, World!');
        expect(textElement).toBeInTheDocument();
      });
      
      // react-testing-library v14 以降での例
      
      import React from 'react';
      import { render, screen } from '@testing-library/react';
      import MyComponent from './MyComponent';
      
      test('MyComponent renders correctly', () => {
        render(<MyComponent />);
      
        const textElement: HTMLElement = screen.getByText('Hello, World!');
        expect(textElement).toBeInTheDocument();
      });
      
      • 上記のコードはあくまで一例であり、実際のテストコードはコンポーネントやテスト対象に合わせて 작성する必要があります。
      • TypeScript を使用する場合は、@types/react@types/react-dom の型宣言ファイルがインストールされていることを確認してください。



      React、TypeScript、単体テストにおける「Cannot find module 'react-dom/client' from 'node_modules/@testing-library/react/dist/pure.js'」エラーの解決策:代替案

      jsdom を使用する

      jsdom は、Node.js 上で JavaScript と HTML を実行するための環境を提供します。この環境を使用することで、ブラウザなしで React コンポーネントの単体テストを実行できます。

      以下の手順を実行して、jsdom を使用して React コンポーネントの単体テストを実行します。

      1. jsdom@testing-library/jest-dom パッケージをインストールします。
      npm install --save-dev jsdom @testing-library/jest-dom
      
      1. jest の設定ファイル (通常は jest.config.js) で、以下の設定を追加します。
      module.exports = {
        preset: 'env',
        setupFilesAfterEnv: [
          'jest-dom/extend-expect',
          './setupTests.js', // カスタム設定ファイル (オプション)
        ],
        testEnvironment: 'jsdom',
      };
      
      1. setupTests.js ファイルを作成し、以下のコードを追加します。
      const jsdom = require('jsdom');
      
      global.window = new jsdom.JSDOM().window;
      global.document = global.window.document;
      
      Object.keys(jsdom.window).forEach((property) => {
        if (typeof global[property] === 'undefined') {
          global[property] = jsdom.window[property];
        }
      });
      
      1. 上記の設定が完了したら、react-testing-library を通常通り使用して、React コンポーネントの単体テストを実行できます。

      babel-jest は、Jest で Babel を使用するためのプラグインです。このプラグインを使用することで、Jest で ES6 や TypeScript のコードを実行できます。

      1. babel-jest パッケージをインストールします。
      npm install --save-dev babel-jest
      
      1. .babelrc ファイルを作成し、以下の設定を追加します。
      {
        "presets": ["env", "react-app"],
        "plugins": ["transform-runtime"]
      }
      
        module.exports = {
          preset: 'env',
          transform: {
            '.js': 'babel-jest',
            '.jsx': 'babel-jest',
          },
        };
        

          moduleNameMapper オプションを使用する

          Jest の moduleNameMapper オプションを使用して、モジュールのエイリアスを定義できます。このオプションを使用することで、react-dom/client モジュールを react-dom モジュールにエイリアスすることができます。

            module.exports = {
              preset: 'env',
              moduleNameMapper: {
                '^react-dom/client$': 'react-dom',
              },
            };
            

            注意事項

            • 上記の代替案は、すべての状況でうまくいくとは限りません。使用する前に、それぞれの方法の制限事項を理解しておくことが重要です。
            • 問題が解決しない場合は、React、TypeScript、Jest、および単体テストに関するオンラインリソースを参照するか、開発コミュニティに助けを求めることをお勧めします。

            reactjs typescript unit-testing


            Redux初心者でも安心!Reducer内でアクションをディスパッチする完全ガイド

            答え: はい、可能です。ただし、いくつかの注意点があります。基本的な流れReduxでは、状態管理は以下の流れで行われます。コンポーネントは、アクションオブジェクトを作成してディスパッチします。ストアはアクションを受け取り、該当するレデューサーに渡します。...


            Reactで高階コンポーネントを使う:propsでコンポーネントに機能を追加

            最も簡単な方法は、渡したいコンポーネントを直接propsとして渡す方法です。このコードでは、MyComponentをAppコンポーネントのchildrenpropsとして渡しています。React. createElementを使って、コンポーネントとそのpropsを動的に生成することもできます。...


            React Router v4 で迷わないナビゲーションメニュー作成:NavLink と Link の決定的な違い

            アクティブなリンクの強調表示: <NavLink> は、現在の URL と一致するリンクを自動的にハイライトする active プロパティを持ちます。これは、ナビゲーションメニューやタブバーなどのインターフェースで、ユーザーが現在どのページにいるのかを視覚的に示すのに役立ちます。...


            JavaScriptでReactのuseStateフックを使って状態オブジェクトを賢く更新する方法

            以下、useState フックを使用して状態オブジェクトを更新およびマージする一般的な方法をいくつかご紹介します。個別プロパティの更新最も単純な方法は、個々のプロパティを直接更新することです。これは、更新するプロパティがわかっている場合に適しています。...