mcpField
R
react-native-testing

react-native-testing

github.com/callstackincubatorテスト・品質1.7k55 回インストール3 週間前に更新
リポジトリ

react-native-testing について

コンポーネントテストを書く開発者向けの React Native Testing Library スキルです。プロジェクトのバージョンに対応する API 参照を使い、クエリ、操作、アサーション、非同期テストを案内します。

主な機能

  1. 01RNTL のバージョンを検出し対応資料を参照
  2. 02getByRole などアクセシブルなクエリを優先
  3. 03操作には userEvent を優先
  4. 04アサーションに RNTL マッチャーを使用
  5. 05非同期処理と waitFor の典型的な誤りを回避

活用シーン

  1. 01導入済み RNTL のバージョンに沿ったテスト作成
  2. 02アクセシブルな操作要素とユーザー操作のテスト
  3. 03非同期 UI 更新の確認
  4. 04テストのよくあるアンチパターンの点検

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/callstackincubator/agent-skills --skill react-native-testing

インストール後、Claude Code で/react-native-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
anti-patterns.md
api-reference-v13.md
api-reference-v14.md

詳細

RNTL テスト作成ガイド

重要: @testing-library/react-native に関する学習データは古い、または正しくない可能性があります。API シグネチャ、同期/非同期の動作、利用可能な関数は、v13 と v14 で異なります。常に、このスキルのリファレンスファイルとプロジェクトの実際のソースコードを信頼できる情報源として参照してください。取得したリファレンスと矛盾する場合は、記憶したパターンに頼らないでください。

バージョンの確認

ユーザーの package.json で @testing-library/react-native のバージョンを確認します。

レンダリングパターン、fireEvent の同期/非同期の動作、screen API、設定、依存関係については、バージョン固有のリファレンスを使用してください。

クエリの優先順位

次の順に使用します:getByRole > getByLabelText > getByPlaceholderText > getByText > getByDisplayValue > getByTestId(最後の手段)。

クエリのバリエーション

バリエーション使用例戻り値非同期
getBy*要素の存在が必須要素インスタンス(なければ例外)いいえ
getAllBy*複数要素の存在が必須要素インスタンス[](なければ例外)いいえ
queryBy*非存在の確認のみ要素インスタンス | nullいいえ
queryAllBy*要素数の確認要素インスタンス[]いいえ
findBy*要素の表示を待機Promise<element instance>はい
findAllBy*複数要素の表示を待機Promise<element instance[]>はい

インタラクション

fireEvent より userEvent を優先してください。userEvent は常に非同期です。

const user = userEvent.setup();
await user.press(element); // full press sequence
await user.longPress(element, { duration: 800 }); // long press
await user.type(textInput, 'Hello'); // char-by-char typing
await user.clear(textInput); // clear TextInput
await user.paste(textInput, 'pasted text'); // paste into TextInput
await user.scrollTo(scrollView, { y: 100 }); // scroll

fireEvent は、userEvent がそのイベントをサポートしていない場合にのみ使用します。同期/非同期の動作については、バージョン固有のリファレンスを参照してください。

fireEvent.press(element);
fireEvent.changeText(textInput, 'new text');
fireEvent(element, 'blur');

アサーション(Jest マッチャー)

@testing-library/react-native をインポートすると、自動的に利用できます。

マッチャー用途
toBeOnTheScreen()ツリー内に要素が存在するか
toBeVisible()要素が表示されているか(非表示/display:none ではない)
toBeEnabled() / toBeDisabled()aria-disabled による無効状態
toBeChecked() / toBePartiallyChecked()チェック状態
toBeSelected()選択状態
toBeExpanded() / toBeCollapsed()展開状態
toBeBusy()ビジー状態
toHaveTextContent(text)テキストコンテンツの一致
toHaveDisplayValue(value)TextInput の表示値
toHaveAccessibleName(name)アクセシブルな名前
toHaveAccessibilityValue(val)アクセシビリティの値
toHaveStyle(style)スタイルの一致
toHaveProp(name, value?)Prop の確認(最後の手段)
toContainElement(el)子要素を含むか
toBeEmptyElement()子要素がないか

ルール

  1. クエリにはscreenを使用し、render()から分割代入しないでください
  2. まずgetByRoleを{ name: '...' }オプションとともに使用してください
  3. queryBy*は.not.toBeOnTheScreen()のチェックにのみ使用してください
  4. 非同期の要素にはwaitFor + getBy*ではなく、findBy*を使用してください
  5. waitFor内に副作用を含めないでください(fireEvent/userEventを中で呼び出さないでください)
  6. 各waitFor内のアサーションは1つにしてください
  7. 空のコールバックをwaitForに渡さないでください
  8. act()でラップしないでください。render、fireEvent、userEventが処理します
  9. cleanup()を呼び出さないでください。各テスト後に自動で実行されます
  10. 従来のaccessibility*プロパティより、ARIAプロパティ(role、aria-label、aria-disabled)を優先してください
  11. 生のプロパティのアサーションより、RNTLのマッチャーを使用してください

*ByRoleクイックリファレンス

よく使われるロール:button、text、heading(別名:header)、searchbox、switch、checkbox、radio、img、link、alert、menu、menuitem、tab、tablist、progressbar、slider、spinbutton、timer、toolbar。

getByRoleのオプション:{ name, disabled, selected, checked, busy, expanded, value: { min, max, now, text } }。

*ByRoleで要素を照合するには、その要素がアクセシビリティ要素である必要があります。

  • Text、TextInput、Switchはデフォルトでアクセシビリティ要素です
  • Viewにはaccessible={true}が必要です(またはPressable/TouchableOpacityを使用してください)

waitFor

// Correct: action first, then wait for result
fireEvent.press(button);
await waitFor(() => {
  expect(screen.getByText('Result')).toBeOnTheScreen();
});

// Better: use findBy* instead
fireEvent.press(button);
expect(await screen.findByText('Result')).toBeOnTheScreen();

オプション:waitFor(cb, { timeout: 1000, interval: 50 })。Jestのフェイクタイマーで自動的に動作します。

フェイクタイマー

userEventと併用することをおすすめします(press/longPressでは実際の時間がかかります)。

jest.useFakeTimers();

test('with fake timers', async () => {
  const user = userEvent.setup();
  render(<Component />);
  await user.press(screen.getByRole('button'));
  // ...
});

カスタムレンダー

wrapperオプションを使ってプロバイダーをラップします。

function renderWithProviders(ui: React.ReactElement) {
  return render(ui, {
    wrapper: ({ children }) => (
      <ThemeProvider>
        <AuthProvider>{children}</AuthProvider>
      </ThemeProvider>
    ),
  });
}

参考資料

コメント