Kodokon kodokon.com

الجودة: Testing Library وStrictMode وProfiler

اختبر السلوك بدلاً من التطبيق، واستثمر الاستدعاءات المزدوجة لـ StrictMode، وقِس عمليات العرض بواسطة Profiler.

10 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

فلسفة Testing Library تتلخّص في جملة واحدة: اختبر ما يدركه المستخدم، لا تفاصيل التطبيق أبداً. عملياً، تستعلم الـ DOM عبر شجرة إمكانية الوصول: getByRole أولاً (ملكة الاستعلامات، التي تتحقّق في طريقها من أدوار ARIA)، ثم getByLabelText وgetByText، وأخيراً getByTestId كملاذ أخير فقط. للتفاعلات، فضّل user-event على fireEvent: فحيث يُطلِق fireEvent.change حدثاً معزولاً، يُعيد user.type إنتاج التسلسل الكامل (focus، keydown، keypress، input، keyup)، تماماً مثل لوحة مفاتيح حقيقية. متغيّرات findBy* تجمع بين استعلام وانتظار غير متزامن: لا غنى عنها بعد خطوة تحميل.

JSX
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('adds a task to the list', async () => {
  const user = userEvent.setup();
  render(<TodoApp />);

  await user.type(
    screen.getByRole('textbox'),
    'Review the report'
  );
  await user.click(
    screen.getByRole('button', { name: /add/i })
  );

  expect(
    await screen.findByText('Review the report')
  ).toBeInTheDocument();
});
اختبار يركّز على السلوك، لا على التطبيق.

StrictMode أداة تطوير من دون أيّ أثر إطلاقاً في الإنتاج. في التطوير، يستدعي دوال مكوّناتك، ومُهيّئات الحالة، والدوال المُمرَّرة إلى setState مرّتين، لاستخراج عمليات العرض غير النقيّة: إذا أعطى التنفيذان نتيجتين مختلفتين، فلديك أثر جانبي خفيّ. ومنذ React 18، يُشغّل أيضاً كل تأثير عبر دورة التركيب، الفكّ، إعادة التركيب: التأثير الذي لا يكون تنظيفه متناظراً تماماً (اشتراك لم يُلغَ أبداً، طلب لم يُجهَض أبداً) يفضح نفسه فوراً. إنه تحضير مباشر لميزات يفكّ فيها React شاشةً ثم يعيد تركيبها مع الحفاظ على حالتها.

JSX
useEffect(() => {
  const controller = new AbortController();
  fetch('/api/user', { signal: controller.signal })
    .then((res) => res.json())
    .then(setUser)
    .catch(() => {});
  return () => controller.abort();
}, []);
تأثير متناظر ينجو من التركيب المزدوج لـ StrictMode.

للقياس، يوفّر React المكوّن <Profiler> ونظيره الرسومي في الـ DevTools. يتلقّى نداؤه المرتجَع onRender، من بين أمور أخرى، phase (mount أو update أو nested-update)، وactualDuration (الوقت المُنفَق فعلاً في عرض الشجرة الفرعية لهذا الإيداع)، وbaseDuration (تقدير للوقت اللازم لعرض الشجرة الفرعية بأكملها من دون أيّ حفظ في الذاكرة). الفجوة بينهما تقيس فعالية memo وuseMemo لديك: actualDuration أدنى بكثير من baseDuration يعني أن الحفظ في الذاكرة يعمل لصالحك.

JSX
import { Profiler } from 'react';

function App() {
  return (
    <Profiler
      id="Sidebar"
      onRender={(id, phase, actualDuration) => {
        console.log(id, phase, actualDuration);
      }}
    >
      <Sidebar />
    </Profiler>
  );
}
قياس تكلفة العرض الحقيقية لشجرة فرعية.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. لماذا يركّب StrictMode كل تأثير، ثم يفكّه، ثم يعيد تركيبه في التطوير؟
    • لمحاكاة زمن استجابة شبكة الخادم
    • للتحقّق من أن تنظيف كل تأثير متناظر
    • لمسح ذاكرة React الداخلية المؤقّتة
    • لإجبار تجميع التحديثات
  2. أيّ استعلام في Testing Library ينبغي أن تلجأ إليه أولاً؟
    • getByTestId، الأكثر ثباتاً
    • getByClassName، الأكثر دقّة
    • getByRole، المتوائم مع شجرة إمكانية الوصول
    • querySelector، الأكثر مرونة
  3. ماذا يمثّل baseDuration في نداء Profiler المرتجَع؟
    • وقت آخر إيداع فقط
    • وقت العرض المُقدَّر للشجرة الفرعية من دون أيّ حفظ في الذاكرة
    • الوقت المنقضي منذ تركيب المكوّن
    • متوسّط مدّة عمليات العرض العشر الأخيرة