web-testing-react-testing-library
React Testing Libraryを用いて、Reactコンポーネントのテストを、アクセシビリティを重視しつつ、ユーザー操作や非同期処理も含めて効率的に行うための様々な手法を習得するSkill。
📜 元の英語説明(参考)
React Testing Library patterns - query hierarchy, userEvent, async utilities, renderHook, custom render with providers, accessibility-first testing
🇯🇵 日本人クリエイター向け解説
React Testing Libraryを用いて、Reactコンポーネントのテストを、アクセシビリティを重視しつつ、ユーザー操作や非同期処理も含めて効率的に行うための様々な手法を習得するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o web-testing-react-testing-library.zip https://jpskill.com/download/10313.zip && unzip -o web-testing-react-testing-library.zip && rm web-testing-react-testing-library.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10313.zip -OutFile "$d\web-testing-react-testing-library.zip"; Expand-Archive "$d\web-testing-react-testing-library.zip" -DestinationPath $d -Force; ri "$d\web-testing-react-testing-library.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
web-testing-react-testing-library.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
web-testing-react-testing-libraryフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
React Testing Library のパターン
クイックガイド: ユーザーインタラクションとアクセシブルなクエリを通じて React コンポーネントをテストします。主要なクエリとして
getByRoleを使用します。fireEventよりもuserEventを優先します。非同期コンテンツにはfindBy*を使用します。実装の詳細ではなく、ユーザーの動作をテストします。
<critical_requirements>
重要: この Skill を使用する前に
すべてのコードは CLAUDE.md のプロジェクト規約に従う必要があります (kebab-case, named exports, import ordering,
import type, named constants)
(クエリの優先順位の階層を必ず使用してください: getByRole > getByLabelText > getByText > getByTestId)
(現実的なユーザーインタラクションのために、fireEvent の代わりに userEvent を必ず使用してください)
(非同期コンテンツには、waitFor + getBy* の代わりに findBy* クエリを必ず使用してください)
(ユーザーに見える動作を必ずテストしてください。内部状態のような実装の詳細ではありません)
(クエリには screen オブジェクトを必ず使用してください。分割代入された render の戻り値ではありません)
</critical_requirements>
自動検出: React Testing Library, @testing-library/react, render, screen, userEvent, fireEvent, waitFor, findBy, getByRole, getByLabelText, renderHook, within, cleanup, prettyDOM, configure, logRoles, logTestingPlaygroundURL
使用する場面:
- ユーザーインタラクションを通じた React コンポーネントの動作のテスト
- アクセシブルな要素のレンダリングと存在の検証
- フォームのインタラクション、バリデーション、および送信のテスト
- 非同期コンポーネントの状態 (ローディング、エラー、成功) のテスト
renderHookを使用したカスタム React hooks のテスト- プロバイダーを使用したカスタム render 関数の作成
使用しない場面:
- 複数のページにまたがる E2E テスト (E2E テストツールに委ねます)
- ネットワークリクエストのモック設定 (API モックソリューションに委ねます)
- React を使用しない純粋なユーティリティ関数のテスト (ユニットテストを直接使用します)
- テストランナーの設定 (テストランナースキルに委ねます)
カバーする主要なパターン:
- クエリの階層と選択戦略
- ユーザーシミュレーションのための userEvent vs fireEvent
- 非同期ユーティリティ (waitFor, findBy クエリ)
- renderHook を使用した hooks のテスト
- プロバイダーを使用したカスタム render
- アクセシビリティテストのパターン
- デバッグユーティリティ (screen.debug, prettyDOM, logRoles)
withinを使用したスコープ付きクエリ- グローバル構成オプション
詳細なリソース:
- コード例については、
examples/フォルダを参照してください:- examples/core.md - クエリ階層の例
- examples/user-events.md - userEvent のパターン
- examples/async-testing.md - findBy, waitFor, waitForElementToBeRemoved
- examples/custom-render.md - プロバイダーを使用したカスタム render
- examples/hooks.md - renderHook のパターン
- examples/accessibility.md - アクセシビリティテストのパターン
- examples/scoped-queries.md - スコープ付きクエリのための within()
- examples/configuration.md - グローバル構成オプション
- 意思決定フレームワークとアンチパターンについては、reference.md を参照してください
<philosophy>
哲学
React Testing Library は、「テストがソフトウェアの使用方法に似ているほど、より確信が得られる」という指針に基づいて構築されています。
コア原則:
- 実装ではなく、ユーザーの動作をテストする: テスト ID や CSS セレクターではなく、ユーザーが要素を見つける方法 (ロール、ラベル、テキスト) で要素をクエリします
- アクセシビリティ優先のテスト: テストで要素を見つけるのが難しい場合、UI にアクセシビリティの問題がある可能性があります
- 実装の詳細をテストしない: 内部状態、refs、またはコンポーネントの内部構造をテストすることは避け、ユーザーが見て操作するものをテストします
- 実際の DOM インタラクション: 実際の統合の問題をキャッチするために、コンポーネントを実際の DOM (jsdom) にレンダリングします
React Testing Library を使用する場面:
- 子要素を持つコンポーネントの統合テスト
- コンポーネント内のユーザーインタラクションフローのテスト
- インタラクティブな要素のアクセシビリティの検証
- フォームのバリデーションと送信のテスト
- props/state に基づく条件付きレンダリングのテスト
使用しない場面:
- 完全なユーザー Journey テスト (E2E テストを使用します)
- 視覚的な外観のテスト (ビジュアルリグレッションツールを使用します)
- ネットワークリクエストの直接テスト (モックされたレスポンスを使用してコンポーネントの動作をテストします)
- サードパーティライブラリの動作のテスト (ライブラリのテストを信頼します)
</philosophy>
<patterns>
コアパターン
パターン 1: クエリの優先順位の階層
アクセシビリティの階層に基づいてクエリを選択します。これにより、テストは、(支援技術を使用するユーザーを含む) ユーザーが UI と対話する方法と一致することが保証されます。
クエリの優先順位
// 優先度 1: すべての人がアクセス可能
getByRole(); // 最高 - アクセシビリティツリーをクエリします
getByLabelText(); // フォームフィールド - ユーザーがフォームをナビゲートする方法
getByPlaceholderText(); // ラベルがない場合 (理想的ではありませんが、必要な場合があります)
getByText(); // 非インタラクティブコンテンツ (div、span、段落)
getByDisplayValue(); // 現在の値によるフォーム要素
// 優先度 2: セマンティッククエリ
getByAltText(); // 画像、エリア、alt を持つ入力
getByTitle(); // 最も信頼性が低い - スクリーンリーダーによって一貫して読み取られるわけではありません
// 優先度 3: テスト ID (最後の手段)
getByTestId(); // 他の方法が失敗した場合のみ
完全なクエリの例については、examples/core.md を参照してください。
この階層の理由: ユーザーは、テスト ID や CSS クラスではなく、表示されているテキスト、ラベル、およびセマンティックロールを通じてアプリと対話します。この方法でテストすることで、アプリのアクセシビリティが確保されます。
パターン 2: fireEvent よりも userEvent
現実的なユーザーインタラクションシミュレーションには userEvent を使用します。実際のインタラクションで生成される完全なイベントチェーンをトリガーします。
主な違い
| アクション | fireEvent |
userEvent |
|---|---|---|
| 入力 | 単一の change イベント |
文字ごとの keyDown、keyPress、keyUp |
| クリック | 単一の click イベント |
(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
React Testing Library Patterns
Quick Guide: Test React components through user interactions and accessible queries. Use
getByRoleas your primary query. PreferuserEventoverfireEvent. UsefindBy*for async content. Test user behavior, not implementation details.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use the query priority hierarchy: getByRole > getByLabelText > getByText > getByTestId)
(You MUST use userEvent instead of fireEvent for realistic user interactions)
(You MUST use findBy* queries for async content instead of waitFor + getBy*)
(You MUST test user-visible behavior, NOT implementation details like internal state)
(You MUST use screen object for queries, NOT destructured render returns)
</critical_requirements>
Auto-detection: React Testing Library, @testing-library/react, render, screen, userEvent, fireEvent, waitFor, findBy, getByRole, getByLabelText, renderHook, within, cleanup, prettyDOM, configure, logRoles, logTestingPlaygroundURL
When to use:
- Testing React component behavior through user interactions
- Verifying accessible element rendering and presence
- Testing form interactions, validation, and submissions
- Testing async component states (loading, error, success)
- Testing custom React hooks with
renderHook - Creating custom render functions with providers
When NOT to use:
- E2E testing spanning multiple pages (defer to your E2E testing tool)
- Network request mocking setup (defer to your API mocking solution)
- Testing pure utility functions without React (use unit tests directly)
- Test runner configuration (defer to your test runner skill)
Key patterns covered:
- Query hierarchy and selection strategy
- userEvent vs fireEvent for user simulation
- Async utilities (waitFor, findBy queries)
- Testing hooks with renderHook
- Custom render with providers
- Accessibility testing patterns
- Debug utilities (screen.debug, prettyDOM, logRoles)
- Scoped queries with
within - Global configuration options
Detailed Resources:
- For code examples, see
examples/folder:- examples/core.md - Query hierarchy examples
- examples/user-events.md - userEvent patterns
- examples/async-testing.md - findBy, waitFor, waitForElementToBeRemoved
- examples/custom-render.md - Custom render with providers
- examples/hooks.md - renderHook patterns
- examples/accessibility.md - Accessibility testing patterns
- examples/scoped-queries.md - within() for scoped queries
- examples/configuration.md - Global configuration options
- For decision frameworks and anti-patterns, see reference.md
<philosophy>
Philosophy
React Testing Library is built on the guiding principle: "The more your tests resemble the way your software is used, the more confidence they can give you."
Core Principles:
- Test User Behavior, Not Implementation: Query elements the way users find them (by role, label, text), not by test IDs or CSS selectors
- Accessibility-First Testing: If your test struggles to find an element, your UI likely has accessibility issues
- No Implementation Details: Avoid testing internal state, refs, or component internals - test what users see and interact with
- Real DOM Interactions: Render components to a real DOM (jsdom) to catch real integration issues
When to use React Testing Library:
- Integration testing components with their children
- Testing user interaction flows within a component
- Verifying accessibility of interactive elements
- Testing form validation and submission
- Testing conditional rendering based on props/state
When NOT to use:
- Full user journey testing (use E2E tests)
- Testing visual appearance (use visual regression tools)
- Testing network requests directly (test component behavior with mocked responses)
- Testing third-party library behavior (trust the library's tests)
</philosophy>
<patterns>
Core Patterns
Pattern 1: Query Priority Hierarchy
Select queries based on accessibility hierarchy. This ensures tests align with how users (including those using assistive technology) interact with your UI.
Query Priority Order
// Priority 1: Accessible to Everyone
getByRole(); // BEST - queries accessibility tree
getByLabelText(); // Form fields - how users navigate forms
getByPlaceholderText(); // When no label (not ideal, but sometimes necessary)
getByText(); // Non-interactive content (divs, spans, paragraphs)
getByDisplayValue(); // Form elements by current value
// Priority 2: Semantic Queries
getByAltText(); // Images, areas, inputs with alt
getByTitle(); // Least reliable - not consistently read by screen readers
// Priority 3: Test IDs (Last Resort)
getByTestId(); // Only when other methods fail
See examples/core.md for complete query examples.
Why this hierarchy: Users interact with your app through visible text, labels, and semantic roles - not through test IDs or CSS classes. Testing this way ensures your app is accessible.
Pattern 2: userEvent Over fireEvent
Use userEvent for realistic user interaction simulation. It triggers the full event chain that real interactions produce.
Key Differences
| Action | fireEvent |
userEvent |
|---|---|---|
| Typing | Single change event |
keyDown, keyPress, keyUp per character |
| Clicking | Single click event |
pointerDown, mouseDown, pointerUp, mouseUp, click |
| Focus | Manual management | Automatic focus management |
Setup Pattern (userEvent v14+)
import userEvent from "@testing-library/user-event";
// Setup BEFORE interactions - creates isolated user session
const user = userEvent.setup();
// Then use throughout test
await user.click(button);
await user.type(input, "Hello");
See examples/user-events.md for complete userEvent examples.
Why userEvent: fireEvent dispatches DOM events directly, bypassing browser event handling. userEvent simulates actual user behavior, triggering the complete event chain including focus, keyboard, and pointer events.
Pattern 3: Async Utilities
Use findBy* queries for elements that appear asynchronously. Use waitFor only for assertions, not element queries.
findBy vs waitFor
// GOOD: findBy for async elements
const button = await screen.findByRole("button", { name: /submit/i });
// BAD: waitFor + getBy for async elements
await waitFor(() => {
screen.getByRole("button", { name: /submit/i }); // DON'T DO THIS
});
waitFor Best Practices
// GOOD: Single assertion in waitFor
await waitFor(() => {
expect(screen.getByText(/success/i)).toBeInTheDocument();
});
// BAD: Multiple assertions in waitFor
await waitFor(() => {
expect(screen.getByText(/success/i)).toBeInTheDocument();
expect(screen.getByText(/complete/i)).toBeInTheDocument(); // DON'T
});
// BAD: Side effects in waitFor
await waitFor(() => {
user.click(button); // DON'T - side effects outside waitFor
expect(result).toBe(true);
});
See examples/async-testing.md for complete async testing examples.
Why this matters: waitFor polls until the callback stops throwing. Multiple assertions or side effects in the callback cause unpredictable behavior and slower test failures.
Pattern 4: Testing Hooks with renderHook
Use renderHook for testing custom hooks in isolation. Prefer testing hooks through components when possible.
Basic renderHook Usage
import { renderHook, act } from "@testing-library/react";
const { result } = renderHook(() => useCounter());
// Access current value
expect(result.current.count).toBe(0);
// Update state with act()
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
With Context Providers
const wrapper = ({ children }: { children: React.ReactNode }) => (
<ThemeProvider theme="dark">{children}</ThemeProvider>
);
const { result } = renderHook(() => useTheme(), { wrapper });
See examples/hooks.md for complete renderHook examples.
When to use renderHook:
- Testing library hooks you're publishing
- Testing complex hook logic in isolation
- Testing hooks with many edge cases
When to prefer component testing:
- The hook is tightly coupled to UI
- You want to test the hook in realistic context
- The component test is simpler to write
Pattern 5: Custom Render with Providers
Create a custom render function that wraps components with all necessary providers.
Custom Render Setup
// test-utils.tsx
import { render, type RenderOptions } from "@testing-library/react";
import type { ReactElement } from "react";
interface AllProvidersProps {
children: React.ReactNode;
}
function AllProviders({ children }: AllProvidersProps) {
// Wrap with your app's providers in correct nesting order
// return (
// <ThemeProvider>
// <AuthProvider>
// {children}
// </AuthProvider>
// </ThemeProvider>
// );
return <>{children}</>;
}
function customRender(
ui: ReactElement,
options?: Omit<RenderOptions, "wrapper">
) {
return render(ui, { wrapper: AllProviders, ...options });
}
// Re-export everything
export * from "@testing-library/react";
export { customRender as render };
See examples/custom-render.md for complete custom render examples.
Why custom render: Avoids repeating provider boilerplate in every test. Creates a consistent test environment matching your app.
Pattern 6: Accessibility Testing Patterns
Use queries that enforce accessibility. If your test struggles to find an element, your UI likely has accessibility issues.
Role-Based Queries
// GOOD: Tests that element is accessible
screen.getByRole("button", { name: /submit/i });
screen.getByRole("textbox", { name: /email/i });
screen.getByRole("checkbox", { name: /agree to terms/i });
screen.getByRole("combobox", { name: /country/i });
// GOOD: Verify accessible names
expect(screen.getByRole("button", { name: /submit/i })).toBeEnabled();
// BAD: Using test IDs when accessible queries work
screen.getByTestId("submit-button"); // DON'T when getByRole works
logRoles for Debugging
import { logRoles } from "@testing-library/react";
// Log all accessible roles in a container
logRoles(container);
See examples/accessibility.md for complete accessibility testing examples.
Why this matters: Screen readers and assistive technologies use the accessibility tree. Testing with accessible queries ensures your app works for all users.
Pattern 7: Debug Utilities
Use debug utilities to understand what's rendered and troubleshoot failing tests.
screen.debug()
// Debug entire document
screen.debug();
// Debug specific element
screen.debug(screen.getByRole("form"));
// Debug multiple elements
screen.debug(screen.getAllByRole("listitem"));
prettyDOM for Custom Output
import { prettyDOM } from "@testing-library/react";
// Get formatted DOM string (for logging, assertions)
const domString = prettyDOM(element);
console.log(domString);
// Customize output length
const domString = prettyDOM(element, 15000); // Increase from 7000 default
logTestingPlaygroundURL
import { logTestingPlaygroundURL } from "@testing-library/react";
// Logs URL to Testing Playground with current DOM
logTestingPlaygroundURL();
// Visit the URL to get suggested queries
When to use debug:
- Test is failing and you don't understand why
- Element can't be found with expected query
- Need to understand current DOM state
Remove before committing: Debug statements are for development only.
Pattern 8: Scoped Queries with within
Use within to scope queries to a specific container element. Essential when testing components with repeated structures.
Basic Usage
import { render, screen, within } from "@testing-library/react";
test("selects item in specific section", () => {
render(<Dashboard />);
// Get a specific section
const sidebar = screen.getByRole("navigation");
// Query only within that section
const homeLink = within(sidebar).getByRole("link", { name: /home/i });
expect(homeLink).toBeInTheDocument();
});
Testing List Items
test("each row has edit button", () => {
render(<UserTable users={mockUsers} />);
const rows = screen.getAllByRole("row");
// Skip header row, check each data row
rows.slice(1).forEach((row) => {
const editButton = within(row).getByRole("button", { name: /edit/i });
expect(editButton).toBeInTheDocument();
});
});
See examples/scoped-queries.md for complete within() examples.
When to use within:
- Components with repeated structures (tables, lists, cards)
- Multiple sections with similar elements
- Testing specific regions of a page
Pattern 9: Global Configuration
Configure Testing Library defaults for your project using configure.
Configuration Options
import { configure } from "@testing-library/react";
// In test setup file
configure({
// Custom test ID attribute (default: "data-testid")
testIdAttribute: "data-test-id",
// Async utility timeout (default: 1000ms)
asyncUtilTimeout: 5000,
// Enable React strict mode warnings in tests
reactStrictMode: true,
});
userEvent Setup Options
import userEvent from "@testing-library/user-event";
// With fake timers - pass your test runner's timer advance function
const user = userEvent.setup({
advanceTimers: vi.advanceTimersByTime, // Required when using fake timers
});
// Skip pointer events check (for elements with pointer-events: none)
const user = userEvent.setup({
pointerEventsCheck: 0, // 0 = never check, 1 = check once, 2 = check per API
});
// Custom delay between events
const user = userEvent.setup({
delay: null, // null = no delay (faster tests)
});
See examples/configuration.md for complete configuration examples.
When to configure:
- Project uses custom test ID attribute
- Tests need longer async timeouts
- Using fake timers with userEvent
</patterns>
<integration>
Integration Guide
Test runner setup:
- Import jest-dom matchers in your test setup file for semantic assertions (
toBeInTheDocument,toHaveValue, etc.) - Cleanup happens automatically in modern setups - no manual
afterEach(cleanup)needed
Mocking approach:
- Mock data at the network boundary, not at the component level
- Set up mock responses before rendering, not after
Framework providers:
- Custom render wraps components with your app's providers (see Pattern 5)
- SSR frameworks may need additional DOM configuration
</integration>
<red_flags>
RED FLAGS
High Priority Issues:
- Using
getByTestIdwhen accessible queries work - Indicates UI may not be accessible, test doesn't reflect user experience - Using
waitForto find elements - UsefindBy*instead, produces better error messages and cleaner code - Using
fireEventfor user interactions - UseuserEventfor realistic event chains - Multiple assertions in single
waitFor- Causes slow test failures and unpredictable behavior - Testing internal component state - Test user-visible behavior, not implementation details
Medium Priority Issues:
- Destructuring render return instead of using
screen-screenprovides cleaner, more maintainable code - Manual
cleanupcalls - Modern frameworks handle cleanup automatically - Wrapping
renderorfireEventinact()- They already wrap inact, double-wrapping is unnecessary - Using
querySelectoror CSS selectors - Use Testing Library queries for accessibility-aligned tests
Common Mistakes:
- Forgetting to
awaituserEvent methods (all are async in v14+) - Using
getBy*for elements that appear asynchronously - Putting side effects inside
waitForcallbacks - Not setting up userEvent before interactions (
const user = userEvent.setup())
Gotchas & Edge Cases:
userEvent.setup()must be called before any interactions (v14+ requirement)queryBy*returnsnullfor missing elements (use for absence assertions only)findBy*has default timeout of 1000ms (configurable via options)result.currentin renderHook is a ref - value updates on each access- Empty
waitFor(() => {})creates fragile timing-dependent tests - Prefer targeted assertions over snapshots - large snapshots produce noise, false positives, and don't communicate test intent
- Snapshot testing is only appropriate for small, stable components with known output (icons, breadcrumbs)
- Remove
screen.debug()calls before committing - they are for development only
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST use the query priority hierarchy: getByRole > getByLabelText > getByText > getByTestId)
(You MUST use userEvent instead of fireEvent for realistic user interactions)
(You MUST use findBy* queries for async content instead of waitFor + getBy*)
(You MUST test user-visible behavior, NOT implementation details like internal state)
(You MUST use screen object for queries, NOT destructured render returns)
Failure to follow these rules will produce brittle tests that don't reflect real user interactions and miss accessibility issues.
</critical_reminders>