第153章:render と screen
React Testing Library の render と screen を使って、
「コンポーネントをテストの世界に連れてきて、画面上の要素を探す」
ところまでやってみます 🧪✨
1️⃣ 今日やることざっくり
この章でゴールにしたいことはこんな感じです👇
renderが「テスト用ブラウザにコンポーネントを映す」役目だとわかる 👀screenが「今映っている画面から要素を探す道具箱」だとわかる 🧰render➜screen.getBy...➜expect(...)の流れで 超シンプルなテストを書けるようになる ✅
環境としては、
- Vite + React + TypeScript プロジェクト
- Vitest + React Testing Library(+ jsdom)
がすでに入っている前提で進めます(前の章でやった想定です)🧡 Vitest が jsdom という「ブラウザもどき」を作ってくれて、 React Testing Library がそこにコンポーネントを描画してくれます。(vitest.dev)
2️⃣ render の役割:テスト用ブラウザに「映す」🎬
🧪 テストでは「別のブラウザ」を使っているイメージ
本物のブラウザでは、
- React が
root要素にコンポーネントを描画して - ユーザーがクリックして…
という流れでしたよね。
テストでは、React Testing Library の render 関数を使って、
「テスト用 DOM(jsdom)」の中にコンポーネントを描画します。(testing-library.com)
「
renderを呼ぶ=テスト専用ブラウザに画面を開く」
みたいなイメージでOKです ✨
🧪 render の基本的な使い方
コンポーネントをテストの世界に呼び出すコードはこんな感じです。
import { render } from '@testing-library/react';
import { MyComponent } from './MyComponent';
render(<MyComponent />);
これだけで、
- テスト用の
document.bodyの中に <MyComponent />が「本物のブラウザ風」に描画されます。(testing-library.com)
render は実は「戻り値」も返していて、そこには
container(描画された DOM)rerender(同じ場所に描画し直す)unmount(消す)- 各種 query(
getByTextなど)
が入っています。(testing-library.com)
でも React Testing Library の公式推しスタイルは、
この戻り値をあまり使わず、代わりに screen を使うやり方です ✅
3️⃣ screen の役割:「今の画面」から要素を探す 🕵️♀️
🧰 screen は「テスト画面のリモコン」
screen は、テスト中の「画面(DOM)」に対して
getByTextgetByRolefindBy...queryBy...
など、要素を探すための関数をまとめて持っているオブジェクトです。(testing-library.com)
よくある書き方はこれ:
import { render, screen } from '@testing-library/react';
render(<MyComponent />); // まず画面に映す
// そのあと、screen から要素を探す
const button = screen.getByRole('button', { name: '送信' });
ポイント 💡
renderが 「画面を映す人」screenが 「映った画面から要素を探す人」
という役割分担になっています。
🌟 なんで screen を使うの?
render の戻り値から getByText などを取り出すこともできますが、
公式ドキュメントでは screen を使うスタイルをおすすめしています。(testing-library.com)
理由イメージはこんな感じ👇
-
screenは常に「今テスト中の画面」を見ている -
テストコードが 「人間の目線」に近い
- 「画面から探す」という読み方になって自然
-
どの
renderの戻り値かを意識しなくていいのでシンプル
「とりあえず
renderとscreenのセットで書く」 これを体にしみこませるのが、この章の目的です ✨
4️⃣ ミニコンポーネントをテストしてみる ✍️
ここからは、実際にファイルを作るイメージで進めます。
🧩 1. テスト対象のコンポーネントを用意
src/components/Hello.tsx を作る想定で書きます。
// src/components/Hello.tsx
export const Hello = () => {
return <h1>こんにちは React テスト 👋</h1>;
};
とてもシンプルなコンポーネントですね 😌
<h1> 見出しを 1 個表示しているだけです。
🧪 2. テストファイルを作成する
次に、同じフォルダにテストファイルを作ります。
ファイル名は Hello.test.tsx とします。
// src/components/Hello.test.tsx
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { Hello } from './Hello';
describe('Hello コンポーネント', () => {
it('見出しが表示される', () => {
// 1. Arrange(準備):コンポーネントをテスト用DOMに描画
render(<Hello />);
// 2. Act(操作):今回は特になし(クリックなどしない)
// 3. Assert(確認):見出しが画面にあるかチェック
const heading = screen.getByRole('heading', {
name: 'こんにちは React テスト 👋',
});
expect(heading).toBeInTheDocument();
});
});
ポイントを一緒に整理してみましょう 📝
🧠 コードの中身を分解してみる
✅ describe / it / expect
Vitest が用意してくれる「テストを書くための関数」です。(vitest.dev)
-
describe('Hello コンポーネント', () => { ... })- テストのグループ(「このコンポーネントのテスト集」みたいな感じ)
-
it('見出しが表示される', () => { ... })- 実際の 1 つのテストケース
-
expect(...).toBeInTheDocument()- 「◯◯であってほしい」という期待(アサーション)
toBeInTheDocumentは@testing-library/jest-domで追加される便利マッチャーです(Zenn)
✅ render(<Hello />);
- React Testing Library の
renderで Helloコンポーネントを テスト用の DOM に描画しています。(testing-library.com)
これを呼ばないと、当然 screen は何も見つけられません。
✅ screen.getByRole('heading', { name: '...' })
screen.getByRoleは「指定したロール(役割)の要素」を探す関数です。role: 'heading'で<h1>〜<h6>を対象にしつつ、name: 'こんにちは React テスト 👋'という「見出しとして読めるテキスト」で絞り込みます。(testing-library.com)
「人間が画面を読むときに、どんな風に見えるか」に近い探し方をしようね、 というのが Testing Library の大事な考え方です 🌱(testing-library.com)
🖥️ 3. テストを実行してみる
プロジェクトのルートで、ターミナル(PowerShell でも OK)から:
npm run test
または
npx vitest
を実行すると、Hello.test.tsx が実行されて、
テスト結果が表示されるはずです ✅
Vitest にはブラウザ UI で結果を見られる --ui オプションもありますが、
それはまたテスト環境回りの章でゆっくり触れましょう。(KENTEM TechBlog)
5️⃣ render と screen の関係を図でイメージする 🎨
テストの流れを Mermaid で図にしてみますね。
ざっくりいうと、
- テストコードが
renderを呼ぶ renderがテスト用 DOM(jsdom)にコンポーネントを描画screenが「今の DOM 全体」を見て、getBy...で要素を探す- 見つけた要素に対して
expectでチェック
という「4ステップの流れ」になっています ✨
6️⃣ よくあるつまずきポイント 😵💫
🐣 ケース1:screen.getByText がエラーになる
Unable to find an element with the text: ...
みたいなエラーが出たときは、まずここをチェック👇
-
本当にそのテキストが画面に出ている?
- 全角・半角・スペース・絵文字の違いなど
-
<h1>ではなく別タグにしていない? -
renderを呼ぶ前にscreen.getBy...していない?
screen.debug() を一度使ってみると、
「今テスト上でどういう HTML が描画されているか」を表示できて便利です。(Cybozu Inside Out | サイボウズエンジニアのブログ)
render(<Hello />);
screen.debug(); // コンソールに今のDOMがドーンと出る
🐣 ケース2:render をインポートし忘れた
テストの先頭で
import { render, screen } from '@testing-library/react';
を入れ忘れると当然エラーになります。 補完が効いているはずなので、VS Code に頼りまくってOKです 💻✨
🐣 ケース3:toBeInTheDocument が型エラーになる
TypeScript 的には、
Property 'toBeInTheDocument' does not exist on type 'Assertion'
みたいなエラーになることがあります。 この場合は、Vitest のセットアップファイルで
@testing-library/jest-dom/vitestをちゃんと import しているか- そのファイルを
vitest.config.tsのsetupFilesに設定しているか
を確認してみてください。(Qiita)
(このあたりはテスト環境の章でしっかりやる想定です〜)
7️⃣ まとめ&ミニ課題 🎓
🌈 今日のまとめ
-
render👉 コンポーネントを テスト用 DOM(jsdom) に描画する関数 -
screen👉 「今の画面」から要素を探すための 道具箱オブジェクト -
パターンとしては
render(<Component />);const el = screen.getByRole(...)やscreen.getByText(...)expect(el).toBeInTheDocument();
という流れでテストを書くのが定番スタイル 💃(testing-library.com)
🏋️♀️ ミニ課題(やってみよう!)
時間があれば、こんな練習をしてみてください 💪
-
「ボタンだけ」のコンポーネントを作る
- ファイル名:
src/components/SimpleButton.tsx - 中身:
<button>ログイン</button>だけ
- ファイル名:
-
そのコンポーネントに対して、テストを書く
render(<SimpleButton />);screen.getByRole('button', { name: 'ログイン' })で探すexpectで存在チェック
-
余裕があったら…
- ボタンのラベルを別の文字に変えて、
- テストが失敗 ➜ ラベルを直す ➜ テストが成功 というサイクルを体験してみてください 🌀
次の章では、getBy... / findBy... / queryBy... の違いを見ていきます。
render + screen のペアは、これからずーっと使う大事な相棒なので、
今のうちに「なんとなく手が自然に動く」くらいまで慣れていきましょ〜 🧡