اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW
حاكِ طلبات HTTP باستخدام Mock Service Worker لاختبار المكوّنات التي تجلب البيانات.
اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW درس مجاني في React Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في React Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة React Academy 4 دروس في المجموع.
لماذا Mock Service Worker؟
يعترض MSW طلبات HTTP على مستوى الشبكة باستخدام Service Worker في المتصفح أو معترض http في Node، مما يتيح لك محاكاة واجهات API دون تعديل شيفرة تطبيقك.
تثبيت MSW
ثبّت MSW وأعدّ معترض Node لاختبارات Jest أو Vitest.
// npm install msw --save-dev
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/users', () => {
return HttpResponse.json([{ id: 1, name: 'Alice' }]);
}),
];إعداد خادم المحاكاة
أنشئ مثيلًا من setupServer مع معالجاتك، واستدعِ server.listen() قبل الاختبارات، وserver.resetHandlers() بعد كل اختبار، وserver.close() بعد انتهائها جميعًا.
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());اختبار مكوّن ينفّذ جلبًا
اعرض المكوّن الذي يطلق طلب fetch. يعترض MSW الطلب ويُرجع بيانات محاكاة. تحقّق مما يراه المستخدم بعد تحميل البيانات.
test('shows user list after fetch', async () => {
render(<UserList />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
expect(await screen.findByText('Alice')).toBeInTheDocument();
});استعلامات findBy لواجهة المستخدم غير المتزامنة
تُرجع استعلامات findBy وعدًا يُحلّ عند ظهور العنصر، بمهلة انتظار تصل إلى ثانية واحدة افتراضيًا. استخدمها للمحتوى الذي يظهر بعد العمليات غير المتزامنة.
// findByText waits for the element to appear
const username = await screen.findByText('Alice');
expect(username).toBeInTheDocument();
// waitFor wraps assertions that need to wait
await waitFor(() => {
expect(screen.getByText('3 users')).toBeInTheDocument();
});تجاوز المعالجات لكل اختبار
استخدم server.use() داخل اختبار لإضافة معالج يُستخدم مرة واحدة ويتجاوز المعالج الافتراضي في ذلك الاختبار فقط.
test('shows error on API failure', async () => {
server.use(
http.get('/api/users', () => {
return HttpResponse.json({ message: 'Server error' }, { status: 500 });
})
);
render(<UserList />);
expect(await screen.findByText('Failed to load users')).toBeInTheDocument();
});اختبار حالات التحميل
تحقّق من مؤشر التحميل مباشرةً بعد العرض، وبشكل متزامن، قبل وصول البيانات غير المتزامنة.
test('shows loading state initially', () => {
render(<UserList />);
expect(screen.getByRole('progressbar')).toBeInTheDocument();
// or
expect(screen.getByText('Loading...')).toBeInTheDocument();
});اختبار طلبات POST
عرّف معالج POST يتحقق من صحة جسم الطلب ويعيد المورد الذي أُنشئ. تحقّق من أن المكوّن يعكس حالة النجاح.
server.use(
http.post('/api/users', async ({ request }) => {
const body = await request.json();
return HttpResponse.json({ id: 2, ...body }, { status: 201 });
})
);
test('creates a user', async () => {
const user = userEvent.setup();
render(<NewUserForm />);
await user.type(screen.getByLabelText('Name'), 'Bob');
await user.click(screen.getByRole('button', { name: /create/i }));
expect(await screen.findByText('User created!')).toBeInTheDocument();
});التأخيرات الشبكية لاختبارات واقعية
أضف تأخيرات اصطناعية إلى المعالجات لاختبار واجهة التحميل بشكل أكثر شمولًا، باستخدام الأداة المساعدة delay في MSW.
import { delay } from 'msw';
http.get('/api/users', async () => {
await delay(200);
return HttpResponse.json([{ id: 1, name: 'Alice' }]);
})الاختبار باستخدام React Query
أحط المكوّن بـ QueryClientProvider جديد في كل اختبار لمنع تسرّب الحالة بين الاختبارات.
function renderWithQuery(ui: React.ReactElement) {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return render(
<QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>
);
}التحقق من بيانات الطلب
استخدم أداة spy لمراقبة الطلب داخل معالج للتحقق من أن التطبيق أرسل جسم الطلب أو الترويسات الصحيحة.
let capturedBody: unknown;
server.use(
http.post('/api/login', async ({ request }) => {
capturedBody = await request.json();
return HttpResponse.json({ token: 'abc' });
})
);
test('sends credentials to API', async () => {
// ... submit form ...
expect(capturedBody).toEqual({ email: 'a@b.com', password: 'pass' });
});استخدام MSW في المتصفح أثناء التطوير
يعمل MSW أيضًا في المتصفح أثناء التطوير. نفّذ npx msw init public/ لتثبيت عامل الخدمة، واستورد معالجاتك في main.tsx لتوفير API وهمية أثناء التطوير المحلي.
تحقق سريع
ما نوع استعلام RTL الذي ينبغي استخدامه للتحقق من محتوى يظهر بعد اكتمال استدعاء API؟
خلاصة
يعترض MSW طلبات HTTP الحقيقية، مما يجعل الاختبارات واقعية من دون الاتصال بخادم مباشر. استخدم server.use() لتجاوز المعالجات في كل اختبار، وfindBy لإجراء التحققات غير المتزامنة، وأحط اختبارات React Query بـ QueryClientProvider جديد.
الأسئلة الشائعة
هل درس «اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW» مجاني؟
نعم — نص درس «اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة React Academy، انتقل إلى CoddyKit PRO. تتضمن دورة React Academy 4 دروس في المجموع.
ماذا ستتعلم في «اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW»؟
حاكِ طلبات HTTP باستخدام Mock Service Worker لاختبار المكوّنات التي تجلب البيانات. تتمرن على React Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ React Academy؟
لا تُشترط خبرة سابقة. React Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس React Academy هذا؟
نعم. كل درس في React Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- اختبار التكامل باستخدام React Testing Library
- اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW
- البدء باستخدام Playwright لتطبيقات React
- اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية