このチュートリアルでは、ウェブブラウザで React アプリケーションをテストするために、jasmine-browser-runner をセットアップする方法を説明します。Webpack と Babel で構築された他の種類のアプリケーションをテストする場合も、同様のプロセスに従うことができます。
このセットアップの 完全な動作例 も利用できます。
前提条件
- アプリケーションが既にビルドされ、実行されていること。
- Node 18 以降がインストールされていること。
- Webpack の設定ファイルを編集することに慣れているか、少なくとも試してみる意思があること。
- Firefox でスペックを実行したい場合は、お使いの Firefox のバージョンと互換性のある geckodriver のバージョンが、
$PATH
のどこかにインストールされていること。 - Chrome でスペックを実行したい場合は、お使いの Chrome のバージョンと互換性のある chromedriver のバージョンが、
$PATH
のどこかにインストールされていること。
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 を使用してアプリケーションをセットアップした場合、次の依存関係も追加する必要があるかもしれません
cross-env
- インストールされている
webpack
のバージョンに対応するwebpack-cli
のバージョン react-scripts
が依存しているものと同じバージョンのbabel-loader
。
インストールされているパッケージのバージョンは、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"
}
}
specDir
と specFiles
の値は、WebPack 設定からの出力パスに対応している必要があります。この場合は dist/test.js
です。
Firefox を使用しない場合は、ブラウザ名を chrome
、safari
、または MicrosoftEdge
に変更します。
次に、package.json
の scripts
セクションに以下を追加します
"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 で動作する前にいくつかの翻訳が必要です。特に
test()
の Jasmine の同等のものはit()
です。- 多くの重複がありますが、Jest と Jasmine には異なる組み込みのマッチャーがあります。
- Jest は各ファイルに暗黙的なトップレベルのスイートを作成します。Jasmine はそうではないため、各ファイルの内容を適切に名前を付けた
describe
でラップすることを強くお勧めします。
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.json
の test
スクリプトの最後に --browser=headlessChrome
を追加します
"test": "npm run test:build && jasmine-browser-runner runSpecs --browser=headlessChrome",