0Pricing
React Native Academy · บทเรียน

การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library

ใช้ render จาก @testing-library/react-native เพื่อเมาท์ส่วนประกอบ ค้นหาองค์ประกอบด้วยข้อความหรือ testID และตรวจสอบว่าเนื้อหาที่คาดไว้แสดงอยู่

การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน React Native Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

What Is React Native Testing Library?

React Native Testing Library (RNTL) is the standard tool for writing component tests in React Native. It lets you render a component in a simulated environment, query the output for elements, and make assertions about what the user would see.

RNTL follows the Testing Library philosophy: test components the way users interact with them — by visible text, accessibility labels, and roles — rather than by internal implementation details like component names or state values. This produces tests that are resilient to refactoring.

Installing React Native Testing Library

Install RNTL and its peer dependency @testing-library/jest-native for extended matchers. The jest-native package adds React Native-specific matchers like toBeVisible() and toHaveTextContent().

Add the setup file to your Jest config so the matchers are available in every test file without manual imports. Import @testing-library/jest-native/extend-expect in the Jest setup file.

npm install --save-dev @testing-library/react-native @testing-library/jest-native

// jest.config.js — add setup file
module.exports = {
  preset: 'jest-expo',
  setupFilesAfterFramework: ['@testing-library/jest-native/extend-expect'],
};

// Or in package.json:
'jest': {
  'preset': 'jest-expo',
  'setupFilesAfterFramework': ['@testing-library/jest-native/extend-expect']
}

Rendering a Component with render()

The render() function from RNTL mounts a component and returns a set of query utilities for inspecting the rendered output. It takes JSX just like you would write in your app, including any props or wrapping providers needed.

The returned object includes query methods and a debug() function that prints the rendered component tree to the console. Call debug() at any point during a test to see what the component looks like at that moment.

import { render } from '@testing-library/react-native';
import { Greeting } from '../src/components/Greeting';

describe('Greeting', () => {
  it('displays the correct greeting message', () => {
    const { getByText, debug } = render(<Greeting name='Alice' />);

    // Print the component tree for debugging
    debug();

    // Assert that the text 'Hello, Alice!' is visible
    expect(getByText('Hello, Alice!')).toBeTruthy();
  });
});

Querying by Text with getByText

getByText(text) finds an element that displays the exact text string. It throws if no matching element is found (failing the test) or if multiple elements match. Use queryByText when you want to assert the text is not present (it returns null instead of throwing).

You can also pass a regular expression to match partial text: getByText(/Hello/). This is useful when the text includes dynamic values like a username that you do not want to hard-code in the test.

import { render } from '@testing-library/react-native';
import { PostCard } from '../src/components/PostCard';

it('renders the post title and author', () => {
  const { getByText, queryByText } = render(
    <PostCard title='My First Post' author='Alice' isDeleted={false} />
  );

  // getByText throws if not found
  expect(getByText('My First Post')).toBeTruthy();
  expect(getByText('Alice')).toBeTruthy();

  // queryByText returns null if not found — use for absence checks
  expect(queryByText('Deleted')).toBeNull();
});

Querying by testID

When there is no user-visible text to query by, add a testID prop to the element and query it with getByTestId('testID'). This is useful for icons, images, loading indicators, and container views.

Keep testID values consistent with the component they identify. A naming convention like componentName-element (e.g., profileCard-avatar) makes test IDs self-documenting and prevents collisions across the test suite.

// Component:
export function LoadingScreen() {
  return (
    <View testID='loading-screen'>
      <ActivityIndicator testID='loading-spinner' />
      <Text>Loading your data...</Text>
    </View>
  );
}

// Test:
import { render } from '@testing-library/react-native';

it('shows a loading spinner', () => {
  const { getByTestId } = render(<LoadingScreen />);

  const spinner = getByTestId('loading-spinner');
  expect(spinner).toBeTruthy();
});

Accessibility Queries

RNTL encourages querying by accessibility attributes because these are what screen readers use, making your tests also verify accessibility. The key accessibility queries are:

  • getByRole('button', { name: 'Submit' }) — finds an element by its ARIA role and accessible name
  • getByLabelText('Email') — finds an element with a matching accessibilityLabel
  • getByPlaceholderText('Enter email') — finds a TextInput by its placeholder
it('has an accessible submit button', () => {
  const { getByRole, getByLabelText, getByPlaceholderText } = render(
    <LoginForm />
  );

  // Find by role (button)
  const submitButton = getByRole('button', { name: 'Sign In' });
  expect(submitButton).toBeTruthy();

  // Find TextInput by placeholder
  const emailInput = getByPlaceholderText('Enter your email');
  expect(emailInput).toBeTruthy();

  // Find by accessibility label
  const passwordInput = getByLabelText('Password');
  expect(passwordInput).toBeTruthy();
});

Asserting with jest-native Matchers

@testing-library/jest-native extends Jest with semantic matchers that are easier to read and more meaningful than checking raw props. Key matchers include:

  • toBeVisible() — element is not hidden
  • toHaveTextContent('text') — element contains the given text
  • toBeDisabled() — button or input is disabled
  • toHaveStyle({ color: 'red' }) — element has the specified style
import { render } from '@testing-library/react-native';
import { StatusBadge } from '../src/components/StatusBadge';

it('shows an error badge in red when status is error', () => {
  const { getByTestId } = render(<StatusBadge status='error' />);

  const badge = getByTestId('status-badge');
  expect(badge).toBeVisible();
  expect(badge).toHaveTextContent('Error');
  expect(badge).toHaveStyle({ backgroundColor: '#ff4444' });
});

Rendering with Providers

Most real-world components depend on context providers like NavigationContainer, Redux Provider, or custom ThemeContext. If you render a component without its required providers, the test will throw.

Create a custom renderWithProviders utility that wraps components in all the necessary providers. Pass this utility to RNTL's render option via wrapper, or use it as a drop-in replacement for render across your test suite.

// test-utils.tsx
import { NavigationContainer } from '@react-navigation/native';
import { ThemeProvider } from '../src/context/ThemeContext';

export function renderWithProviders(
  ui: React.ReactElement,
  options = {}
) {
  function Wrapper({ children }: { children: React.ReactNode }) {
    return (
      <NavigationContainer>
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </NavigationContainer>
    );
  }
  return render(ui, { wrapper: Wrapper, ...options });
}

// In tests:
import { renderWithProviders } from '../test-utils';
const { getByText } = renderWithProviders(<ProfileScreen />);

Snapshot Testing

Snapshot tests capture the rendered output of a component and save it to a .snap file. On subsequent runs, Jest compares the current output against the saved snapshot and fails the test if they differ. This catches unintentional UI changes.

Use snapshots sparingly. They are great for small, stable components like icons or buttons. For complex screens, snapshot tests tend to be brittle — minor, intentional changes require updating the snapshot with jest --updateSnapshot, making it easy to accidentally accept broken output.

import { render } from '@testing-library/react-native';
import { PrimaryButton } from '../src/components/PrimaryButton';

it('renders a primary button correctly', () => {
  const { toJSON } = render(<PrimaryButton title='Save' onPress={() => {}} />);
  expect(toJSON()).toMatchSnapshot();
});

// First run creates:
// __snapshots__/PrimaryButton.test.tsx.snap
// Subsequent runs compare against that snapshot

Testing Conditional Rendering

Components often render different UI based on props or state. Test each conditional branch explicitly by rendering the component with different props and asserting that the correct elements are present or absent.

Use queryByText or queryByTestId (which return null instead of throwing) to assert absence. Avoid using getBy queries to assert absence — they throw, which does not produce a clear failure message.

describe('ErrorBanner', () => {
  it('shows the error message when error prop is provided', () => {
    const { getByText } = render(
      <ErrorBanner error='Something went wrong' />
    );
    expect(getByText('Something went wrong')).toBeTruthy();
  });

  it('renders nothing when error is null', () => {
    const { queryByTestId } = render(<ErrorBanner error={null} />);
    // Assert the banner container is NOT rendered
    expect(queryByTestId('error-banner')).toBeNull();
  });
});

The getAllBy and findBy Variants

RNTL query functions come in three variants:

  • getBy — throws if not found or if multiple matches (use for single, must-exist elements)
  • getAllBy — returns an array, throws if none found (use for lists of elements)
  • findBy — returns a Promise, waits for the element to appear (use for async content)

The findBy variants are essential when testing components that load data asynchronously — they automatically retry the query until the element appears or a timeout is exceeded.

// getAllBy: asserts there are exactly 3 list items
const items = getAllByTestId('list-item');
expect(items).toHaveLength(3);

// findBy: waits for async content to appear
it('shows posts after loading', async () => {
  const { findByText } = render(<PostFeed />);

  // Waits up to 1000ms for the text to appear
  const postTitle = await findByText('My First Post');
  expect(postTitle).toBeTruthy();
});

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: how to render components with RNTL's render() function and query elements by text, testID, and accessibility attributes, how jest-native matchers like toBeVisible() and toHaveTextContent() make assertions more readable, and how to wrap components in providers for tests that require navigation or theme context. Next up we fire user events and test interactive component behavior.

คำถามที่พบบ่อย

บทเรียน “การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library”

ใช้ render จาก @testing-library/react-native เพื่อเมาท์ส่วนประกอบ ค้นหาองค์ประกอบด้วยข้อความหรือ testID และตรวจสอบว่าเนื้อหาที่คาดไว้แสดงอยู่ คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Native Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Native Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Native Academy นี้ได้ไหม

ได้ บทเรียน React Native Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การตั้งค่า Jest ในโปรเจกต์ React Native
  2. การเรนเดอร์ส่วนประกอบด้วย React Native Testing Library
  3. การส่งเหตุการณ์และการทดสอบการโต้ตอบของผู้ใช้
  4. การจำลองโมดูลเนทีฟและโค้ดแบบอะซิงโครนัส
← กลับไปที่ React Native Academy