セットアップ
React Testing Library
は、使用するために特別な設定を必要としません。しかし、テストフレームワークを設定する際に、定型コードを減らすためにできることがいくつかあります。このドキュメントではJestの設定方法を説明しますが、他のテストフレームワークでも同様の設定が可能です(React Testing LibraryはJestの使用を必須としていません)。
グローバル設定
グローバルテスト設定にオプションを追加することで、個々のファイルのテストのセットアップとティアダウンを簡素化できます。
カスタムレンダリング
グローバルコンテキストプロバイダー、データストアなどを含むカスタムレンダリングメソッドを定義すると便利な場合があります。これをグローバルに利用できるようにするには、React Testing Library
からすべてを再エクスポートするユーティリティファイルを定義する方法があります。すべてのインポートで、React Testing Libraryをこのファイルに置き換えることができます。相対パスを使用せずにテストユーティリティファイルにアクセスできるようにする方法については、以下を参照してください。
以下の例では、render
にwrapper
オプションを使用してデータプロバイダーを設定しています。
- JavaScript
- TypeScript
- import { render, fireEvent } from '@testing-library/react';
+ import { render, fireEvent } from '../test-utils';
import React from 'react'
import {render} from '@testing-library/react'
import {ThemeProvider} from 'my-ui-lib'
import {TranslationProvider} from 'my-i18n-lib'
import defaultStrings from 'i18n/en-x-default'
const AllTheProviders = ({children}) => {
return (
<ThemeProvider theme="light">
<TranslationProvider messages={defaultStrings}>
{children}
</TranslationProvider>
</ThemeProvider>
)
}
const customRender = (ui, options) =>
render(ui, {wrapper: AllTheProviders, ...options})
// re-export everything
export * from '@testing-library/react'
// override render method
export {customRender as render}
- import { render, fireEvent } from '@testing-library/react';
+ import { render, fireEvent } from '../test-utils';
import React, {ReactElement} from 'react'
import {render, RenderOptions} from '@testing-library/react'
import {ThemeProvider} from 'my-ui-lib'
import {TranslationProvider} from 'my-i18n-lib'
import defaultStrings from 'i18n/en-x-default'
const AllTheProviders = ({children}: {children: React.ReactNode}) => {
return (
<ThemeProvider theme="light">
<TranslationProvider messages={defaultStrings}>
{children}
</TranslationProvider>
</ThemeProvider>
)
}
const customRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>,
) => render(ui, {wrapper: AllTheProviders, ...options})
export * from '@testing-library/react'
export {customRender as render}
注意
上記の例で名前付きエクスポートをオーバーライドしようとすると、Babelバージョン7未満ではエラーが発生します。#169と以下の回避策を参照してください。
Babel 6の回避策
ESモジュールではなく、Nodeで動作するはずのCommonJSモジュールを使用できます
const rtl = require('@testing-library/react')
const customRender = (ui, options) =>
rtl.render(ui, {
myDefaultOption: 'something',
...options,
})
module.exports = {
...rtl,
render: customRender,
}
カスタムクエリの追加
注意
一般的に、react-testing-library用のカスタムクエリを作成する必要はありません。使用する場合は、新しいクエリが実装の詳細をテストせずに、ユーザー中心の方法でテストすることを推奨しているかどうかを検討する必要があります。
カスタムクエリドキュメントに記載されているように、またはbuildQueries
ヘルパーを使用して、独自のカスタムクエリを定義できます。その後、queries
オプションを使用して、任意のレンダリングコールでそれらを使用できます。カスタムクエリをグローバルに利用できるようにするには、以下に示すように、カスタムレンダリングメソッドに追加します。
以下の例では、Cypress.ioドキュメントで言及されている「テストID」規則であるdata-cy
で要素を取得するための一連の新しいクエリバリアントが作成されます。
- JavaScript
- TypeScript
import {queryHelpers, buildQueries} from '@testing-library/react'
// The queryAllByAttribute is a shortcut for attribute-based matchers
// You can also use document.querySelector or a combination of existing
// testing library utilities to find matching nodes for your query
const queryAllByDataCy = (...args) =>
queryHelpers.queryAllByAttribute('data-cy', ...args)
const getMultipleError = (c, dataCyValue) =>
`Found multiple elements with the data-cy attribute of: ${dataCyValue}`
const getMissingError = (c, dataCyValue) =>
`Unable to find an element with the data-cy attribute of: ${dataCyValue}`
const [
queryByDataCy,
getAllByDataCy,
getByDataCy,
findAllByDataCy,
findByDataCy,
] = buildQueries(queryAllByDataCy, getMultipleError, getMissingError)
export {
queryByDataCy,
queryAllByDataCy,
getByDataCy,
getAllByDataCy,
findAllByDataCy,
findByDataCy,
}
import {
queryHelpers,
buildQueries,
Matcher,
MatcherOptions,
} from '@testing-library/react'
// The queryAllByAttribute is a shortcut for attribute-based matchers
// You can also use document.querySelector or a combination of existing
// testing library utilities to find matching nodes for your query
const queryAllByDataCy = (
container: HTMLElement,
id: Matcher,
options?: MatcherOptions | undefined,
) => queryHelpers.queryAllByAttribute('data-cy', container, id, options)
const getMultipleError = (c, dataCyValue) =>
`Found multiple elements with the data-cy attribute of: ${dataCyValue}`
const getMissingError = (c, dataCyValue) =>
`Unable to find an element with the data-cy attribute of: ${dataCyValue}`
const [
queryByDataCy,
getAllByDataCy,
getByDataCy,
findAllByDataCy,
findByDataCy,
] = buildQueries(queryAllByDataCy, getMultipleError, getMissingError)
export {
queryByDataCy,
queryAllByDataCy,
getByDataCy,
getAllByDataCy,
findAllByDataCy,
findByDataCy,
}
その後、queries
オプションを渡すことで、レンダリング関数を使用して新しいクエリをオーバーライドおよび追加できます。
カスタムクエリをグローバルに追加する場合は、カスタマイズしたrender
、screen
、およびwithin
メソッドを定義することでこれを行うことができます
- JavaScript
- TypeScript
import {render, queries, within} from '@testing-library/react'
import * as customQueries from './custom-queries'
const allQueries = {
...queries,
...customQueries,
}
const customScreen = within(document.body, allQueries)
const customWithin = element => within(element, allQueries)
const customRender = (ui, options) =>
render(ui, {queries: allQueries, ...options})
// re-export everything
export * from '@testing-library/react'
// override render method
export {customScreen as screen, customWithin as within, customRender as render}
import {render, queries, within, RenderOptions} from '@testing-library/react'
import * as customQueries from './custom-queries'
import {ReactElement} from 'react'
const allQueries = {
...queries,
...customQueries,
}
const customScreen = within(document.body, allQueries)
const customWithin = (element: ReactElement) => within(element, allQueries)
const customRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'queries'>,
) => render(ui, {queries: allQueries, ...options})
export * from '@testing-library/react'
export {customScreen as screen, customWithin as within, customRender as render}
その後、他のクエリと同様にカスタムクエリを使用できます
const {getByDataCy} = render(<Component />)
expect(getByDataCy('my-component')).toHaveTextContent('Hello')
Jestとテストユーティリティの設定
相対インポート(../../test-utils
)を使用せずにJestテストファイルでカスタムテストファイルにアクセスできるようにするには、ファイルを含むフォルダーをJest moduleDirectories
オプションに追加します。
これにより、test-utilsディレクトリ内のすべての.js
ファイルが../
なしでインポート可能になります。
- import { render, fireEvent } from '../test-utils';
+ import { render, fireEvent } from 'test-utils';
module.exports = {
moduleDirectories: [
'node_modules',
+ // add the directory with the test-utils.js file, for example:
+ 'utils', // a utility folder
+ __dirname, // the root directory
],
// ... other options ...
}
TypeScriptを使用している場合は、これをtsconfig.json
にマージします。TypeScriptなしでCreate React Appを使用している場合は、代わりにjsconfig.json
に保存します。
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"test-utils": ["./utils/test-utils"]
}
}
}
Jest 28
Jest 28以降を使用している場合、jest-environment-jsdomパッケージを個別にインストールする必要があります。
- npm
- Yarn
npm install --save-dev jest-environment-jsdom
yarn add --dev jest-environment-jsdom
また、jsdom
はデフォルトの環境ではなくなりました。 jest.config.js
を編集することで、グローバルにjsdom
を有効にすることができます
module.exports = {
+ testEnvironment: 'jsdom',
// ... other options ...
}
または、一部のテストでのみjsdom
が必要な場合は、docblocksを使用して必要に応じて有効にすることができます
/**
* @jest-environment jsdom
*/
Jest 27
Jestの最新バージョン(27)を使用している場合、jsdom
はデフォルトの環境ではなくなりました。 jest.config.js
を編集することで、グローバルにjsdom
を有効にすることができます
module.exports = {
+ testEnvironment: 'jest-environment-jsdom',
// ... other options ...
}
または、一部のテストでのみjsdom
が必要な場合は、docblocksを使用して必要に応じて有効にすることができます
/**
* @jest-environment jsdom
*/
Jest 24(またはそれ以前)とデフォルト
デフォルト設定でJestテストフレームワークバージョン24以前を使用している場合、JestはReact Testing Libraryで必要な機能と修正が不足しているバージョンのjsdom環境を使用しているため、jest-environment-jsdom-fifteen
パッケージを使用することをお勧めします。
まず、jest-environment-jsdom-fifteen
をインストールします。
- npm
- Yarn
npm install --save-dev jest-environment-jsdom-fifteen
yarn add --dev jest-environment-jsdom-fifteen
次に、testEnvironment
としてjest-environment-jsdom-fifteen
を指定します
module.exports = {
+ testEnvironment: 'jest-environment-jsdom-fifteen',
// ... other options ...
}
Jestを使用しない場合
webpack(または類似のもの)にバンドルされたブラウザでテストを実行している場合、React Testing Library
はそのまま使用できます。ただし、React Testing Libraryを使用しているほとんどの人は、JestテストフレームワークでtestEnvironment
をjest-environment-jsdom
に設定して使用しています(これはJest 26以前のデフォルト設定です)。
jsdom
は、Nodeで実行されるDOMおよびブラウザAPIの純粋なJavaScript実装です。Jestを使用しておらず、Nodeでテストを実行したい場合は、jsdomを自分でインストールする必要があります。また、ブラウザAPIをシミュレートするためにグローバル環境を設定するために使用できるglobal-jsdom
と呼ばれるパッケージもあります。
まず、jsdom
とglobal-jsdom
をインストールします。
- npm
- Yarn
npm install --save-dev jsdom global-jsdom
yarn add --dev jsdom global-jsdom
mochaを使用すると、テストコマンドは次のようになります
mocha --require global-jsdom/register
自動クリーンアップのスキップ
使用しているテストフレームワークがafterEach
グローバル(mocha、Jest、Jasmineなど)をサポートしている場合、デフォルトでは各テスト後にCleanup
が自動的に呼び出されます。ただし、RTL_SKIP_AUTO_CLEANUP
環境変数を「true」に設定することで、自動クリーンアップをスキップすることを選択できます。これは、cross-env
を使用して次のように行うことができます
cross-env RTL_SKIP_AUTO_CLEANUP=true jest
これをさらに簡単にするために、@testing-library/react/dont-cleanup-after-each
をインポートするだけで、同じことができます。 @testing-library/react
をインポートする前に、必ずこれを行ってください。これは、JestのsetupFiles
設定を使用して行うことができます
{
// ... other jest config
setupFiles: ['@testing-library/react/dont-cleanup-after-each']
}
または、mochaの-r
フラグを使用します
mocha --require @testing-library/react/dont-cleanup-after-each
あるいは、cleanup
を実行したくないすべてのテストで@testing-library/react/pure
をインポートすることもできます。そうすれば、afterEach
は自動的に設定されません。
Mochaのウォッチモードでの自動クリーンアップ
Mochaをウォッチモードで使用する場合、グローバルに登録されたクリーンアップは、各テスト後に初めてのみ実行されます。そのため、後続の実行は、* TestingLibraryElementError:複数の要素が見つかりました *エラーで失敗する可能性が高くなります。
Mochaのウォッチモードで自動クリーンアップを有効にするには、クリーンアップルートフックを追加します。次の内容でmocha-watch-cleanup-after-each.js
ファイルを作成します
const {cleanup} = require('@testing-library/react')
exports.mochaHooks = {
afterEach() {
cleanup()
},
}
そして、mochaの-r
フラグを使用して登録します
mocha --require ./mocha-watch-cleanup-after-each.js