دليل React Testing Library: شرح عملي لاختبار تطبيقات React مع أمثلة JavaScript

دقائق القراءة: 6
شرح React Testing Library واختبار تطبيقات React باستخدام JavaScript

ما هي React Testing Library ولماذا تُعد مهمة؟

تساعدك مكتبة React Testing Library على اختبار تطبيقات React بطريقة قريبة جداً من تجربة المستخدم الحقيقية. وبدلاً من التركيز على تفاصيل التنفيذ الداخلية داخل المكونات، فإنها تختبر ما يظهر فعلياً في شجرة DOM بعد التصيير داخل المتصفح.

الفكرة الأساسية في هذه المكتبة بسيطة: كلما كان الاختبار مشابهاً للطريقة التي يستخدم بها الزائر التطبيق، زادت ثقتك بأن التطبيق سيعمل كما هو متوقع في الواقع. ولهذا توفر المكتبة أدوات بحث وتفاعل تتعامل مع العناصر كما يراها المستخدم، مثل النصوص والأدوار والعناوين والوصف البديل.

هذا الشرح يفترض أن لديك معرفة أساسية بلغة JavaScript وبكيفية عمل React.

كيف تعمل React Testing Library في بيئة React؟

عند إنشاء مشروع جديد بواسطة Create React App أو CRA، ستجد أن كلّاً من React Testing Library وJest مضمَّنان افتراضياً. وهذا يعني أن أغلب ما تحتاجه هو كتابة اختباراتك فقط.

أما إذا كنت تستخدم المكتبة خارج بيئة CRA، فعليك تثبيت الأدوات المطلوبة يدوياً:

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

السبب في تثبيت Jest هو أن React Testing Library توفر أدوات تساعدك على كتابة الاختبارات، لكنها ليست إطاراً كاملاً لتشغيلها. لذلك تحتاج إلى مشغّل اختبارات مثل Jest، ويمكن أيضاً استخدام بدائل مثل Mocha أو Jasmine، لكن Jest يظل خياراً ممتازاً مع React.

إنشاء مشروع تجريبي لاختبار React

للبدء، يمكنك إنشاء مشروع جديد باستخدام القالب الافتراضي:

npx create-react-app react-test-example

بعد إنشاء المشروع، ستجد ملفاً باسم App.test.js داخل مجلد src. وغالباً سيكون محتواه مشابهاً لما يلي:

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

شرح أول اختبار باستخدام render() وscreen

في المثال السابق، تُستخدم الدالة render() من مكتبة React Testing Library لتصيير المكوّن App بشكل افتراضي وإلحاقه داخل document.body. بعد ذلك يمكنك الوصول إلى العناصر الناتجة عبر الكائن screen.

البحث هنا تم بواسطة الدالة getByText()، وهي تبحث عن عنصر يحمل النص Learn React. ثم تأتي مرحلة التحقق باستخدام expect() من Jest للتأكد من أن العنصر موجود بالفعل داخل المستند عبر toBeInTheDocument().

expect(linkElement).toBeInTheDocument();

إذا لم يتم العثور على العنصر، فسيعتبر Jest أن الاختبار فشل.

عرض شجرة العناصر الناتجة أثناء الاختبار

إذا أردت معرفة ما الذي تم تصييره فعلياً داخل الصفحة أثناء تنفيذ الاختبار، يمكنك استخدام الدالة screen.debug():

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  screen.debug();
});

بعد ذلك شغّل الأمر التالي من الطرفية:

npm run test

ستظهر لك شجرة document.body كاملة في وحدة التحكم، وهو ما يفيدك كثيراً عند تتبع البنية الفعلية للعناصر أثناء كتابة الاختبارات.

<body>
  <div>
    <div class="App">
      <header class="App-header">
        <img alt="logo" class="App-logo" src="logo.svg" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          class="App-link"
          href="https://reactjs.org"
          rel="noopener noreferrer"
          target="_blank"
        >
          Learn React
        </a>
      </header>
    </div>
  </div>
</body>

أهم طرق البحث عن العناصر في React Testing Library

معظم اختبارات React تعتمد على العثور على العناصر بطريقة صحيحة. وتوفر المكتبة عدة دوال تسهّل ذلك، وأفضلها هي التي تحاكي سلوك المستخدم الحقيقي.

  • getByText(): للبحث عن العنصر عبر النص الظاهر.
  • getByRole(): للبحث حسب قيمة role.
  • getByLabelText(): للبحث عبر النص المرتبط بـ label.
  • getByPlaceholderText(): للعثور على العنصر من خلال قيمة placeholder.
  • getByAltText(): للبحث في الصور والعناصر التي تستخدم alt.
  • getByDisplayValue(): للبحث حسب القيمة الحالية، ويُستخدم غالباً مع عناصر <input>.
  • getByTitle(): للبحث باستخدام الخاصية title.

تسمح لك هذه الأساليب بكتابة اختبارات أكثر وضوحاً وقرباً من الاستخدام الفعلي للتطبيق.

متى تستخدم getByTestId()؟

إذا لم تنجح كل الطرق السابقة في تحديد العنصر المطلوب، يمكنك اللجوء إلى getByTestId()، وهي تبحث بالاعتماد على الخاصية data-testid:

import { render, screen } from '@testing-library/react';

render(<div data-testid="custom-element" />);
const element = screen.getByTestId('custom-element');

لكن من المهم الانتباه إلى أن استخدام data-testid لا يعكس الطريقة التي يتعامل بها المستخدم الحقيقي مع التطبيق، لذلك يُنصح باستخدامه كخيار أخير فقط. في أغلب الحالات، يكون البحث بالنص أو الدور أو الوسم المرتبط أفضل بكثير من ناحية الجودة وسهولة الصيانة.

اختبار تفاعلات المستخدم في React

لا يقتصر دور React Testing Library على التحقق من وجود العناصر فقط، بل يساعدك أيضاً على اختبار سلوك المستخدم، مثل الضغط على زر أو إدخال نص داخل حقل.

ولتنفيذ هذه التفاعلات بشكل واقعي، يُستخدم غالباً الملحق @testing-library/user-event، وهو مكتبة مرافقة مخصّصة لمحاكاة تفاعل المستخدم مع الواجهة.

مثال عملي: اختبار زر تبديل النمط بين الفاتح والداكن

لنفترض أن لديك مكوّناً بسيطاً يبدّل بين النمط light وdark:

import React, { useState } from "react";

function App() {
  const [theme, setTheme] = useState("light");

  const toggleTheme = () => {
    const nextTheme = theme === "light" ? "dark" : "light";
    setTheme(nextTheme);
  };

  return (
    <button onClick={toggleTheme}>
      Current theme: {theme}
    </button>
  );
}

export default App;

الآن يمكنك كتابة اختبار يبحث عن الزر ثم يحاكي النقر عليه باستخدام userEvent.click(). بعد ذلك نتحقق من أن النص تغير إلى dark:

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";

test("Test theme button toggle", () => {
  render(<App />);
  const buttonEl = screen.getByText(/Current theme/i);
  userEvent.click(buttonEl);
  expect(buttonEl).toHaveTextContent(/dark/i);
});

هذه الطريقة توضح كيف يمكن لاختباراتك أن تتحقق من السلوك الفعلي للتطبيق بدلاً من الاكتفاء بفحص البيانات الداخلية أو الحالة البرمجية.

أمثلة إضافية على تفاعلات المستخدم

توفر مكتبة user-event وسائل متعددة لمحاكاة التفاعل، من أبرزها:

  • click() للنقر على العناصر.
  • dblClick() للنقر المزدوج.
  • type() لإدخال نص داخل الحقول.

وكلما استخدمت هذه الأدوات بطريقة واقعية، أصبحت اختباراتك أكثر دقة وفائدة عند تطوير واجهات الاستخدام.

أفضل ممارسات كتابة اختبارات قوية وقابلة للصيانة

  • اختبر ما يراه المستخدم، لا التفاصيل الداخلية للمكوّن.
  • ابدأ بأساليب البحث الدلالية مثل getByRole() وgetByText().
  • استخدم getByTestId() فقط عند الضرورة القصوى.
  • اكتب أسماء اختبارات توضّح السلوك المتوقع بوضوح.
  • اختبر التفاعل والنتيجة النهائية معاً، لا مجرد وجود العنصر.

هذه الممارسات تجعل الاختبارات أسهل فهماً وأقل هشاشة عند تعديل الشيفرة مستقبلاً.

لماذا يُفضَّل اختبار السلوك بدلاً من تفاصيل التنفيذ؟

المستخدم الحقيقي لا يرى قيم state ولا خصائص props داخل مكونات React. ما يراه فقط هو عناصر الواجهة الناتجة داخل المتصفح. لهذا تشجّع React Testing Library على اختبار السلوك النهائي الظاهر، لأن هذا النوع من الاختبارات يعكس تجربة الاستخدام الفعلية بصورة أفضل.

وعندما تنجح اختباراتك المبنية على هذا المبدأ، يمكنك أن تطمئن أكثر إلى أن التطبيق سيتصرف كما ينبغي في بيئة الإنتاج.

كتاب لتعلم JavaScript الحديثة بشكل تدريجي للمبتدئين والمطورين

متى تكون هذه المكتبة الخيار المناسب لك؟

إذا كنت تطور واجهات React وتهتم بكتابة اختبارات عملية يمكن الوثوق بها، فإن React Testing Library تُعد من أفضل الخيارات. فهي مناسبة للمشاريع الصغيرة والمتوسطة والكبيرة، خصوصاً عندما تريد تقليل الاختبارات المرتبطة بالتفاصيل الداخلية والتركيز على تجربة الاستخدام.

الخلاصة التقنية

تعتمد قوة React Testing Library على فلسفة واضحة: اختبر ما يهم المستخدم فعلاً. لذلك فهي لا تدفعك إلى فحص بنية المكونات الداخلية بقدر ما توجهك إلى اختبار الواجهة وسلوكها الظاهر. تقنياً، هذا الأسلوب ينتج اختبارات أكثر استقراراً وأسهل صيانة، ويمنح فرق التطوير ثقة أكبر عند تحديث المكونات أو إعادة هيكلتها دون كسر المنطق الأساسي للتطبيق.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *