Supertest لـ JavaScript (Node.js): دليل شامل مع أمثلة
مرحبًا بكم في PythonLib! في هذه المقالة، سنشرح بالتفصيل مكتبة Supertest — واحدة من أشهر الأدوات لاختبار HTTP في بيئة Node.js. إذا كنت تطور تطبيقات ويب باستخدام Express أو Koa أو Fastify أو أي إطار عمل آخر، فإن Supertest سيكون مساعدك الأساسي لكتابة اختبارات تكامل موثوقة.
1. ما هي Supertest ولماذا تحتاجها؟
Supertest هي مكتبة عالية المستوى لاختبار خوادم HTTP في Node.js. توفر واجهة برمجة تطبيقات (API) سهلة ومعبرة لإرسال طلبات HTTP إلى تطبيقك والتحقق من الاستجابات. الميزة الرئيسية لـ Supertest هي أنها تسمح لك باختبار الخادم دون الحاجة إلى تشغيله على منفذ حقيقي — تستخدم المكتبة آليات Node.js الداخلية لمحاكاة اتصال HTTP، مما يجعل الاختبارات سريعة ومعزولة.
لماذا تحتاج Supertest؟ في تطوير الويب الحديث، جودة الكود لها أهمية قصوى. تساعد اختبارات التكامل التي تتحقق من عمل نقاط النهاية (endpoints) الخاصة بواجهة API في اكتشاف الانحدارات (regressions) والأخطاء في معالجة الطلبات ومشاكل التحقق من صحة البيانات. تتيح لك Supertest كتابة هذه الاختبارات بشكل موجز وقابل للقراءة، باستخدام سلاسل الطرق (chaining) والتأكيدات المدمجة للتحقق من الحالات والرؤوس ومحتوى الاستجابة وغير ذلك الكثير. تتكامل المكتبة بشكل مثالي مع أدوات تشغيل الاختبارات الشهيرة مثل Jest وMocha وJasmine وAVA.
تم إنشاء المكتبة بواسطة TJ Holowaychuk (مؤلف Express وKoa والعديد من المشاريع المعروفة الأخرى) ومنذ ذلك الحين يتم صيانتها من قبل المجتمع. تم بناء Supertest فوق مكتبة SuperAgent — عميل HTTP قوي لـ Node.js والمتصفح. هذا يعني أنك تحصل على جميع إمكانيات SuperAgent، بما في ذلك دعم أنواع البيانات المختلفة، رفع الملفات، التعامل مع الكوكيز (cookies) وغير ذلك الكثير.
2. التثبيت
يتم تثبيت Supertest عبر مدير الحزم npm. يُوصى بتثبيت المكتبة كاعتماد للتطوير (devDependency)، حيث أنها غير مطلوبة في بيئة الإنتاج (production).
npm install --save-dev supertest
إذا كنت تستخدم yarn:
yarn add --dev supertest
للعمل مع TypeScript، قد تحتاج أيضًا إلى تثبيت الأنواع (types):
npm install --save-dev @types/supertest
لاحظ أن Supertest يتطلب Node.js الإصدار 14 أو أعلى. تأكد أيضًا من أن لديك أداة تشغيل اختبارات مثبتة (مثل Jest أو Mocha).
3. بداية سريعة — مثال عملي بسيط
لنقم بإنشاء تطبيق Express بسيط وكتابة اختبار له باستخدام Supertest. سيوضح هذا المثال الآلية الأساسية لعمل المكتبة.
أولاً، لننشئ ملف app.js مع تطبيقنا:
// app.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.status(200).json({ message: 'Hello, World!' });
});
app.get('/user', (req, res) => {
res.status(200).json({ name: 'John Doe', age: 30 });
});
module.exports = app;
الآن، لننشئ ملف الاختبار app.test.js:
// app.test.js
const request = require('supertest');
const app = require('./app');
describe('GET /', () => {
it('should return Hello, World!', async () => {
const response = await request(app)
.get('/')
.expect(200);
expect(response.body).toEqual({ message: 'Hello, World!' });
});
});
describe('GET /user', () => {
it('should return user data', async () => {
const response = await request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect(200);
expect(response.body.name).toBe('John Doe');
expect(response.body.age).toBe(30);
});
});
لتشغيل الاختبار، استخدم الأمر التالي (إذا كنت تستخدم Jest):
npx jest app.test.js
سترى مخرجات مشابهة لهذا:
PASS ./app.test.js
GET /
✓ should return Hello, World! (15 ms)
GET /user
✓ should return user data (5 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
تهانينا! لقد كتبت أول اختبار لك باستخدام Supertest. لاحظ كيف أننا لم نضطر لتشغيل الخادم على منفذ — لقد قامت Supertest بمعالجة كل شيء داخليًا.
4. الطرق الأساسية (API Methods)
توفر Supertest مجموعة غنية من الطرق لإرسال الطلبات والتحقق من الاستجابات. دعنا نستعرض أهمها مع أمثلة عملية.
4.1. طرق إرسال الطلبات (HTTP Methods)
تدعم Supertest جميع طرق HTTP الشائعة: GET، POST، PUT، DELETE، PATCH، HEAD، OPTIONS. إليك كيفية استخدامها:
const request = require('supertest');
const app = require('./app');
// GET request
request(app).get('/api/users');
// POST request
request(app).post('/api/users').send({ name: 'Ali', email: 'ali@example.com' });
// PUT request
request(app).put('/api/users/1').send({ name: 'Ali Updated' });
// DELETE request
request(app).delete('/api/users/1');
// PATCH request
request(app).patch('/api/users/1').send({ age: 31 });
4.2. إضافة البيانات في الطلب (Request Body)
لإرسال بيانات JSON في جسم الطلب، استخدم الطريقة .send():
it('should create a new user', async () => {
const newUser = {
name: 'Sara Ahmed',
email: 'sara@example.com',
age: 28
};
const response = await request(app)
.post('/api/users')
.send(newUser)
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe('Sara Ahmed');
});
4.3. تعيين رؤوس الطلب (Request Headers)
لتعيين رؤوس مخصصة، استخدم الطريقة .set():
it('should authenticate with token', async () => {
const token = 'my-secret-token';
const response = await request(app)
.get('/api/protected')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(response.body.success).toBe(true);
});
يمكنك أيضًا تعيين رؤوس متعددة في سلسلة واحدة:
request(app)
.get('/api/data')
.set('Accept', 'application/json')
.set('X-Custom-Header', 'custom-value')
.expect(200);
4.4. التحقق من الاستجابة (Response Assertions)
الطريقة .expect() هي الأداة الرئيسية للتحقق من الاستجابة. يمكن استخدامها بعدة طرق:
// التحقق من حالة HTTP
.expect(200)
.expect(404)
.expect(500)
// التحقق من رأس معين
.expect('Content-Type', /json/)
.expect('Content-Length', '42')
// التحقق من جسم الاستجابة
.expect({ message: 'Success' })
.expect('Hello World')
// استخدام دالة مخصصة
.expect((res) => {
if (res.body.error) throw new Error('Unexpected error');
})
4.5. التعامل مع الاستعلامات (Query Parameters)
لإضافة معاملات الاستعلام (query parameters)، استخدم الطريقة .query():
it('should filter users by age', async () => {
const response = await request(app)
.get('/api/users')
.query({ age: 25, city: 'Cairo' })
.expect(200);
expect(response.body.length).toBeGreaterThan(0);
expect(response.body[0].age).toBe(25);
});
5. أمثلة متقدمة
5.1. اختبار رفع الملفات (File Upload)
يدعم Supertest رفع الملفات باستخدام الطريقة .attach():
const path = require('path');
it('should upload a file', async () => {
const filePath = path.join(__dirname, 'test-image.jpg');
const response = await request(app)
.post('/api/upload')
.attach('avatar', filePath)
.expect(200);
expect(response.body.filename).toBeDefined();
});
5.2. اختبار المصادقة (Authentication)
إليك مثال كامل لاختبار عملية تسجيل الدخول:
describe('POST /api/login', () => {
it('should login successfully with valid credentials', async () => {
const credentials = {
email: 'user@example.com',
password: 'password123'
};
const response = await request(app)
.post('/api/login')
.send(credentials)
.expect(200);
expect(response.body).toHaveProperty('token');
expect(response.body.token).toBeTruthy();
});
it('should return 401 for invalid credentials', async () => {
const credentials = {
email: 'wrong@example.com',
password: 'wrongpassword'
};
await request(app)
.post('/api/login')
.send(credentials)
.expect(401);
});
});
5.3. اختبار معالجة الأخطاء (Error Handling)
اختبر كيفية تعامل تطبيقك مع الأخطاء:
describe('Error handling', () => {
it('should return 404 for unknown routes', async () => {
await request(app)
.get('/api/nonexistent')
.expect(404);
});
it('should return 400 for invalid input', async () => {
await request(app)
.post('/api/users')
.send({ name: '' }) // اسم فارغ
.expect(400);
});
it('should return 500 for server errors', async () => {
// محاكاة خطأ في الخادم
await request(app)
.get('/api/trigger-error')
.expect(500);
});
});
6. أفضل الممارسات والنصائح
للاستفادة القصوى من Supertest في مشاريعك، اتبع هذه النصائح:
- استخدم async/await: تجنب استخدام callback functions، واستخدم async/await لجعل الكود أكثر وضوحًا.
- افصل التطبيق عن الخادم: قم بتصدير تطبيق Express الخاص بك (بدون تشغيله) لاستخدامه مباشرة في الاختبارات.
- استخدم beforeEach/afterEach: قم بإعداد قاعدة البيانات أو تنظيفها قبل وبعد كل اختبار لضمان العزلة.
- اختبر الحالات الحدية: لا تختبر فقط المسار السعيد (happy path)، بل اختبر أيضًا حالات الخطأ والمدخلات غير الصالحة.
- اجمع مع Jest أو Mocha: استخدم Supertest مع أدوات الاختبار القوية مثل Jest للحصول على تقارير مفصلة وتغطية كود.
- استخدم .expect() بحكمة: تحقق من الحالة والرؤوس والمحتوى معًا في سلسلة واحدة لقراءة أفضل.
7. الخلاصة
في هذا الدليل الشامل، تعلمنا كيفية استخدام مكتبة Supertest لاختبار تطبيقات Node.js. بدأنا بالتثبيت والبداية السريعة، ثم استعرضنا الطرق الأساسية والمتقدمة مع أمثلة عملية. Supertest هي أداة قوية ومرنة تجعل اختبار API سهلاً وفعالاً.
سواء كنت تستخدم Express أو Koa أو Fastify، فإن Supertest ستساعدك على كتابة اختبارات تكامل موثوقة تضمن جودة تطبيقك. ابدأ الآن في إضافة Supertest إلى مشاريعك واستمتع بتجربة اختبار سلسة!
هل لديك أسئلة أو استفسارات؟ شاركنا في التعليقات أدناه!