このチュートリアルでは、ウェブブラウザで React アプリケーションをテストするために、jasmine-browser-runner をセットアップする方法を説明します。Webpack と Babel で構築された他の種類のアプリケーションをテストする場合も、同様のプロセスに従うことができます。

このセットアップの 完全な動作例 も利用できます。

前提条件

create-react-app を使用してアプリケーションをセットアップした場合、eject する必要はありません。ただし、アプリケーションの別のコピーで eject すると、create-react-app が Webpack と Babel をどのように構成しているかを確認するのに役立ちます。

使用するパッケージ管理ツールを選択してください


依存関係の追加

まだインストールしていない場合は、これらのパッケージをインストールします

$ yarn add --dev jasmine-core jasmine-browser-runner 
$ npm install --save-dev jasmine-core jasmine-browser-runner

create-react-app を使用してアプリケーションをセットアップした場合、次の依存関係も追加する必要があるかもしれません

インストールされているパッケージのバージョンは、npm ls コマンドで確認できます。例: npm ls webpack。(これは、パッケージのインストールに Yarn を使用している場合でも機能します。)

Webpack の設定

次に、スペック用の新しい Webpack 設定ファイル webpack-test.config.js を作成します。これは、アプリケーションの JavaScript コードをパッケージ化するものと似ている必要があります。出力ファイル名を test.js に設定し、エントリをスペックファイルのリストに設定します。(ヒント: ファイルを追加および削除するときに手動でリストを更新する必要がないように、glob を使用します。)

たとえば、メインの Webpack 設定ファイルが次のようになっているとします

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.[hash].js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
    }),
  ],
  resolve: {
    modules: [__dirname, "src", "node_modules"],
    extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: require.resolve("babel-loader"),
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.png|svg|jpg|gif$/,
        use: ["file-loader"],
      }, 
    ],
  },
};

対応する webpack-test.config.js は次のようになる可能性があります

const path = require("path");
const glob = require("glob");

module.exports = {
  entry: glob.sync("spec/**/*Spec.js?(x)"),
  output: {
    filename: "test.js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [],
  resolve: {
    modules: [__dirname, "src", "node_modules"],
    extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: require.resolve("babel-loader"),
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.png|svg|jpg|gif$/,
        use: ["file-loader"],
      }, 
    ],
  },
};

それらの違いは次のとおりです

-const HtmlWebpackPlugin = require("html-webpack-plugin");
 const path = require("path");
+const glob = require("glob");
 
 module.exports = {
-  entry: "./src/index.js",
+  entry: glob.sync("spec/**/*Spec.js?(x)"),
   output: {
-    filename: "bundle.[hash].js",
+    filename: "test.js",
     path: path.resolve(__dirname, "dist"),
   },
-  plugins: [
-    new HtmlWebpackPlugin({
-      template: "./src/index.html",
-    }),
-  ],
+  plugins: [],
   resolve: {
     modules: [__dirname, "src", "node_modules"],
     extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],

上記の例では、スペックファイルが spec ディレクトリに格納され、Spec.js で終わる名前を持つことを前提としています。スペックファイルを別の場所に配置する場合は、glob パターンを変更する必要があります。たとえば、多くの React 開発者は、スペックファイルをテスト対象のコードの隣に置き、.test.js で終わる名前を付けます。これらのファイルと一致させるには、spec/**/*Spec.js(x) の代わりに src/**/*.test.js を使用します。

React インポートの処理

一部の React コードベースでは、JSX 式を含むすべてのファイルの先頭付近に import React from 'react' のようなステートメントがあります。コンパイル時に自動的に追加するために Webpack プラグインを使用するものもあります。コンポーネントのソースファイルを確認してください。上記のような import ステートメントがない場合は、webpack-test.config.ts に次のようなものが含まれていることを確認する必要があります

         test: /\.jsx?$/,
         exclude: /node_modules/,
         loader: require.resolve("babel-loader"),
+        options: {
+          customize: require.resolve('babel-preset-react-app/webpack-overrides'),
+          presets: [
+            [
+              require.resolve('babel-preset-react-app'),
+              { runtime: 'automatic' }
+            ],
+          ],
+        },
       },
       {
         test: /\.css$/,

そうしないと、スペックを実行したときにコンポーネントのソースファイルから ReferenceError: React is not defined のようなエラーがスローされます。

Babel の設定

Babel 設定 がまだない場合は、次の内容で作成します

{
  "presets": [
    "@babel/preset-react",
    "@babel/preset-env"
  ]
}

jasmine-browser-runner の設定

次に、次の内容で spec/support/jasmine-browser.json を作成します

{
  "srcDir": "src",
  "srcFiles": [],
  "specDir": "dist",
  "specFiles": ["test.js"],
  "helpers": [],
  "browser": {
    "name": "firefox"
  }
}

specDirspecFiles の値は、WebPack 設定からの出力パスに対応している必要があります。この場合は dist/test.js です。

Firefox を使用しない場合は、ブラウザ名を chromesafari、または MicrosoftEdge に変更します。

次に、package.jsonscripts セクションに以下を追加します

    "test:build": "cross-env NODE_ENV=test npx webpack --config webpack-test.config.js --mode development",
    "test:watch": "cross-env NODE_ENV=test npx webpack --config webpack-test.config.js --mode development --watch",
    "test": "npm run test:build && jasmine-browser-runner runSpecs",
    "test:serve": "npm run test:build && jasmine-browser-runner"

React Testing Library

React Testing Library は現在、スペックで React コンポーネントをレンダリングして結果をクエリするための最も人気のある選択肢です。一部の代替手段とは異なり、ブラウザで実行できます。設定は簡単です。@testing-library/react パッケージがインストールされていることを確認するだけです。create-react-app の最近のバージョンを使用してアプリケーションを初期化した場合は、既にある可能性があります。そうでない場合は、インストールします

$ yarn add --dev @testing-library/react
$ npm install --save-dev @testing-library/react

詳細については、React Testing Library のドキュメントを参照してください。関連する jasmine-dom マッチャーライブラリも興味深いかもしれません。

React Testing Library ドキュメントのほとんどは Jest 用に記述されているため、コードサンプルは Jasmine で動作する前にいくつかの翻訳が必要です。特に

Jest から Jasmine にコードサンプルを変換するときは、Jasmine チュートリアルJasmine に付属のマッチャーのリスト、および jasmine-dom に付属のマッチャーのリストを参照すると役立つ場合があります。

まとめ

これで完了です。スペックを作成し、以前に作成した Webpack 設定に一致するスペックファイル名を使用して実行します。スペックを実行する方法はいくつかあります

スペックを一度だけ実行するには、yarn test npm test を実行するだけです。これにより、test:build を実行してスペックがコンパイルされ、ブラウザが起動し、ブラウザでスペックが実行され、ブラウザがシャットダウンします。すべて合格した場合は終了コードが 0 になり、それ以外の場合はゼロ以外になります。

Web ページにアクセスしてスペックを実行できるサーバーを起動するには、yarn test:serve npm run test:serve を実行します。これはデバッグに特に役立ちます。変更を加えるときにコードを自動的に再コンパイルするために、yarn test:watch npm run test:watch を実行し続けることもできます。

yarn test npm test でヘッドレスブラウザを使用したい場合は、package.jsontest スクリプトの最後に --browser=headlessChrome を追加します

    "test": "npm run test:build && jasmine-browser-runner runSpecs --browser=headlessChrome",