4.4التحقق وإدارة الأخطاء والاختبارات (Jest)
الأساسي في 30 ثانية
- لا ثقة أبدا بالمدخلات : التحقق (Zod/Joi) قبل المعالجة، والرفض بـ 400 واضح — ضد البيانات الفاسدة والأعطال والثغرات.
- تركيز الأخطاء : وسيط Express (err, req, res, next) في الآخر، وtry/catch على await، و404/400 منتظرة مقابل 500 غير منتظرة.
- منعكس ساليم : الاختبار بـ Jest (وحدوي + مسار) وإعادة التشغيل بعد كل تعديل — عدم الانحدار الذي يحرر.
حالة مصغرة متواصلة — ساليم يجعل الموثوقية قبل الإنتاج
واجهة ساليم (4.1-4.3) تشتغل في العرض، لكن بائعا ينشئ منتجا دون اسم، ومسار يتعطل على معرف مجهول ولا أحد يعرف ماذا يختبر قبل كل تسليم. يضيف ساليم مخطط Zod يرفض الأجسام غير الصالحة بـ 400، ووسيط أخطاء مركزيا يرد بنظافة دون تسريب تفاصيل، ثم يكتب أول اختباراته بـ Jest : دالة مختبَرة معزولة، ومسار مختبَر من البداية إلى النهاية. ومع التعديل التالي، يعيد تشغيل السلسلة في ثوان. آخر محطة في الخيط الرابط : من النموذج الأولي إلى التطبيق الاحترافي.
الحلقة الأخيرة لحالة 4.1-4.3 — يُكمل ساليم المستوى : البناء، والتأمين، والتحريك، وجعل الموثوقية.
1. التحقق من المدخلات
تذكير من 4.2 : لا ثقة أبدا بالمدخلات. قبل معالجة بيانات عميل (جسم، ووسائط)، تحققوا من أنها بالصيغة المنتظرة : الحقول المطلوبة حاضرة، والأنواع صحيحة، والقيود محترمة (بريد صالح، وطول أقصى). إذا كانت غير صالحة : رفض بـ 400 مع رسالة واضحة، قبل أي معالجة. المكتبات : Zod (حديث، وممتاز مع TypeScript — مخطط واحد يحقق ويُنَمِّط) أو Joi (مجرب). يحمي التحقق من البيانات الفاسدة والأعطال وبعض الثغرات — لا غنى عنه لكل مدخل خارجي.
2. إدارة الأخطاء المركزية
في الإنتاج، تقع أخطاء : قاعدة غير متاحة، ومورد غير موجود، وعملية فاشلة. في Express، النمط وسيط إدارة أخطاء مركزي — دالة خاصة بـ 4 وسائط (err, req, res, next)، موضوعة في الآخر : تُوجه إليها الأخطاء فيرجع ردا متسقا (رمز صحيح، ورسالة واضحة، ودون تفاصيل حساسة). نحيط await بـ try/catch (أو غلاف) ونميز الأخطاء المنتظرة (404 و400) عن غير المنتظرة (500).
3. الاختبارات الآلية بـ Jest
بدلا من التحقق باليد (مضن، وناقص، وغير قابل للتكرار)، نكتب كودا يختبر الكود. وJest أشهر إطار في Node : وحدوية (دالة معزولة)، وتكامل (أجزاء عدة، ومسار مع قاعدته)، ومن البداية إلى النهاية. يتحقق اختبار من أن مدخلا يعطي المخرج المنتظر (expect(resultat).toBe(attendu)). الفوائد : ثقة، وعدم انحدار (إعادة التشغيل بعد كل تغيير)، وتوثيق للسلوك، وتصميم أفضل (الكود القابل للاختبار منظم أفضل). التحقق + الأخطاء + الاختبارات : ما يفصل نموذجا أوليا عن تطبيق احترافي.
🔎 مثال ملموس — 🔎 مثال ملموس — التحقق ثم الاختبار
حركتا ساليم على إنشاء المنتج :
المخطط : { nom: سلسلة غير فارغة، وprix: عدد موجب }
← جسم غير صالح : 400 { erreur: 'nom requis, prix positif attendu' }
الاختبار : POST /produits دون اسم ← ننتظر 400
الاختبار : دالة total(panier) ← expect(total).toBe(300)
القراءة : يرفض المخطط قبل المعالجة، ويثبت الاختبار السلوك.
الدرس : 400 واضح للعميل، واختبارات خضراء للفريق.
مفردات القسم
- التحقق من المدخلات
- التحقق من أن البيانات المستلمة بالصيغة المنتظرة (حقول، وأنواع، وقيود) قبل المعالجة ؛ والرفض بـ 400 إذا غير صالحة. الأدوات : Zod وJoi.
مثال بسيط: يرفض مخطط ساليم منتجا دون اسم قبل أي كتابة.
ما ليس كذلك: معالجة req.body مباشرة دون أي ضبط.
رد فعل: لا مدخل خارجي يلمس البيانات دون مخطط.
- وسيط الأخطاء
- دالة Express خاصة (err, req, res, next) موضوعة في الآخر، تركّز الأخطاء وترجع ردا متسقا.
مثال بسيط: لدى ساليم، ينتهي كل خطأ هناك : رمز صحيح، ورسالة واضحة، ودون تسرب حساس.
ما ليس كذلك: try/catch مبعثرة يرجع كل منها صيغة مختلفة.
رد فعل: صيغة خطأ واحدة لكل الواجهة.
- المنتظر مقابل غير المنتظر
- المنتظرة : 404 غير موجود، و400 غير صالح — تُدار صراحة. غير المنتظرة : أعطال ← 500 دون تفاصيل حساسة.
مثال بسيط: يرجع ساليم 404 لمنتج مجهول، و500 عامة لعطل.
ما ليس كذلك: تتبع مكدس خام مرجع إلى العميل في الإنتاج.
رد فعل: يستلم العميل الرمز الصحيح، وليست أسرارنا أبدا.
- الاختبار الآلي (Jest)
- كود يتحقق من الكود : مدخل معطى ← مخرج منتظر (expect().toBe()). وحدوية، وتكامل، ومن البداية إلى النهاية.
مثال بسيط: يختبر ساليم دالة المجموع ثم مسار POST.
ما ليس كذلك: تحقق يدوي وحيد في المتصفح.
رد فعل: كتابة الاختبار الذي يثبت أن هذا يشتغل.
- عدم الانحدار
- إعادة تشغيل الاختبارات بعد كل تعديل لرصد ما كسرناه دون قصد.
مثال بسيط: يعيد ساليم تشغيل سلسلته قبل كل تسليم وينام مطمئنا.
ما ليس كذلك: اكتشاف الكسر في الإنتاج بتذكرة عميل.
رد فعل: سلسلة خضراء مشترطة قبل كل دمج.
في التطبيق — عمليا — جعل واجهة موثوقة (تحقق، وأخطاء، واختبارات)
- تحققوا من مدخلات مسار بـ Zod أو Joi : حددوا مخططا، وارفضوا غير الصالح بـ 400 مع رسالة واضحة.
- ركبوا وسيط الأخطاء المركزي (err, req, res, next) في الآخر ؛ وأحيطوا await بـ try/catch.
- ميزوا أخطاء منتظرة (404 و400) وغير منتظرة (500) ؛ ولا تفشوا أي تفصيل حساس في الإنتاج.
- اكتبوا اختبارات Jest : وحدويا واحدا (expect().toBe()) ومسارا واحدا ؛ وأعيدوها بعد كل تعديل.
نص جاهز للقول — إعلان التوثيق (30 ثانية)
« معكم ساليم : قبل الإنتاج، كل مدخل متحقق منه بمخطط مع رفض بـ 400 واضح، وكل الأخطاء تمر بوسيط مركزي لا يسرب أي تفصيل، وسلسلة Jest تغطي الوحدوي كالمسارات — تُعاد مع كل تعديل لعدم الانحدار. »
يُقال قبل كل إنتاج ؛ واعرضوا السلسلة الخضراء.
نموذج للنسخ واللصق — تحقق Zod + أخطاء + اختبار Jest (كود مختبَر)
// 1) التحقق (npm i zod) + 2) أخطاء مركزية
const express = require('express');
const { z } = require('zod');
const app = express();
app.use(express.json());
const schemaProduit = z.object({
nom: z.string().min(1, 'nom requis'),
prix: z.number().positive('prix positif attendu')
});
const produits = [];
app.post('/api/v1/produits', (req, res, next) => {
try {
const donnees = schemaProduit.parse(req.body); // يرمي خطأ إذا كان غير صالح
const produit = { id: produits.length + 1, ...donnees };
produits.push(produit);
res.status(201).json(produit);
} catch (err) {
err.statut = 400; // منتظرة : مدخل غير صالح
next(err);
}
});
// وسيط الأخطاء : دائما في الآخر
// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
const statut = err.statut || 500;
const message = statut === 500 ? 'Erreur interne' : err.message;
res.status(statut).json({ erreur: message });
});
module.exports = app;
// 3) اختبار Jest (ملف app.test.js، وnpm i -D jest supertest) :
// const request = require('supertest');
// const app = require('./app');
// test('POST sans nom → 400', async () => {
// const res = await request(app).post('/api/v1/produits').send({ prix: 10 });
// expect(res.status).toBe(400);
// });
// test('POST valide → 201', async () => {
// const res = await request(app).post('/api/v1/produits').send({ nom: 'Couscoussier', prix: 2500 });
// expect(res.status).toBe(201);
// expect(res.body.nom).toBe('Couscoussier');
// });
نموذج تعلم أولي
تحقق أدنى + اختباران أو 3 على الحرج : تكوين دون إبطاء الاستكشاف.
واجهة حقيقية في الإنتاج
كما يفعل ساليم : مخطط على كل مدخل خارجي، ووسيط مركزي، وسلسلة Jest خضراء مشترطة قبل الدمج.
مشروع TypeScript
يحقق Zod وينمط : مخطط واحد لأمن التنفيذ ومتانة التجميع.
فريق يكتشف الاختبارات
البدء بالمسارات الحرجة (الإنشاء، والاتصال) : قيمة فورية، وعادة مثبتة.
✓ ممارسات جيدة
- التحقق قبل المعالجة، والرفض بـ 400 واضح.
- تركيز الأخطاء في وسيط وحيد.
- الاختبار وإعادة التشغيل بعد كل تعديل.
✗ أخطاء شائعة
- معالجة req.body دون تحقق.
- إرجاع تتبع المكدس إلى العميل.
- الاختبار باليد فقط، مرة واحدة.
النقاط الأساسية
- التحقق (Zod/Joi) : التحقق من الصيغة/الأنواع/القيود قبل المعالجة، و400 واضح إذا غير صالح. لا ثقة أبدا بالعميل.
- الأخطاء مركزية : وسيط (err, req, res, next) في الآخر ← رد متسق ؛ وإدارة غير المتزامن (try/catch).
- اختبارات JEST : وحدوية + تكامل (مسار). expect(resultat).toBe(attendu).
- الفوائد : ثقة، وعدم انحدار، وتوثيق، وتصميم أفضل. العتبة من النموذج الأولي ← الاحترافي.
تحدي 48 ساعة — طبّق غدا
أضيفوا مخطط تحقق إلى مساركم الأكثر حرجا، ووسيط الأخطاء، واختباري Jest (رفض 400 واحد، ونجاح واحد) — سلسلة خضراء مشترطة.
- أستطيع شرح التحقق ووسيط الأخطاء وJest.
- أعرف كتابة 400 واضح و500 دون تسرب.
- لدي اختباران أخضران على مساري الحرج.
أسئلة شائعة
لماذا نختبر وقد « صار يشتغل » ؟
لأن « يشتغل » لا يساوي إلا الحالات المتحقق منها باليد، اليوم. وغدا، قد يكسر كل تعديل بصمت شيئا آخر (انحدار) — ودون اختبارات، لوجب إعادة التحقق من كل شيء باليد في كل مرة، وهو ما لا يُفعل أبدا. تجلب الاختبارات ثقة (نعرف، ولا نظن)، وعدم انحدار (تنبيه فوري بعد كل تغيير)، وتوثيقا للسلوك المنتظر، وتدفع إلى هيكلة الكود القابل للاختبار أفضل.
التحقق والأخطاء والاختبارات : هل يلزم الكل، لكل المشاريع ؟
كيّلوا حسب الرهان. نموذج أولي سريع الزوال : خففوا للسرعة، لكن مارسوا حدا أدنى (عادات جيدة). تطبيق حقيقي (مستخدمون، وإنتاج، وفريق) : لا غنى عنه — التحقق (بيانات فاسدة، وأعطال، وثغرات)، والأخطاء (وإلا تعطل الخادم أو سرب تفاصيل)، والاختبارات (وإلا مرت الانحدارات حتى الإنتاج). هذه الممارسات الثلاث تحول نموذجا أوليا إلى تطبيق موثوق.
أين نضع وسيط إدارة أخطاء Express ؟