DEV Community

Cover image for اختبار الـ API باستخدام Cypress: كيفية اختبار الواجهات البرمجية بـ cy.request()
Yusuf Khalidd
Yusuf Khalidd

Posted on • Originally published at apidog.com

اختبار الـ API باستخدام Cypress: كيفية اختبار الواجهات البرمجية بـ cy.request()

أنت تستخدم Cypress بالفعل لاختبارات شاملة، لكنك لا تحتاج دائمًا إلى المرور عبر واجهة المستخدم للتحقق من سلوك النظام. عندما تريد استدعاء API مباشرة، فحص رمز الحالة، والتحقق من JSON، استخدم cy.request(). يرسل هذا الأمر طلبات HTTP حقيقية من Node خارج المتصفح، لذلك يمكنك اختبار نقطة نهاية مستقلة أو تجهيز حالة الاختبار قبل تشغيل سيناريو واجهة المستخدم.

جرّب Apidog اليوم

في هذا الدليل ستتعلم كيف تختبر APIs باستخدام Cypress عمليًا: استخدام cy.request()، تأكيد الاستجابات، ربط الطلبات لاستخدام رمز المصادقة، واستخدام cy.intercept() لتزييف طلبات المتصفح. ستعرف أيضًا متى يكون Cypress كافيًا لاختبار API، ومتى تحتاج إلى أداة API متخصصة.

لماذا تختبر APIs باستخدام Cypress

الكثير مما تتحقق منه في اختبارات واجهة المستخدم يعتمد فعليًا على API خلفية:

  • هل يعيد /login رمزًا مميزًا؟
  • هل يعيد /users شكل البيانات الصحيح؟
  • هل ينشئ طلب POST السجل المتوقع؟

اختبار هذه النقاط مباشرة يمنحك فائدتين:

  1. سرعة أعلى: لا يوجد عرض للواجهة ولا انتظار لعناصر DOM.
  2. تجهيز بيانات الاختبار بسهولة: بدلًا من إنشاء مستخدم عبر نموذج التسجيل، أرسل طلب POST واحدًا ثم انتقل مباشرة إلى التأكيد المهم.

إذا كان Cypress موجودًا في مشروعك، يمكنك إضافة اختبارات API داخل نفس ملفات المواصفات، باستخدام نفس expect ونفس تشغيل CI.

أساسيات cy.request()

ينشئ cy.request() طلب HTTP ويعيد الاستجابة. يتم تشغيله من عملية Cypress Node، وليس من المتصفح، لذلك لا يخضع لقيود CORS أو سياسة نفس المصدر.

الصيغ الشائعة:

cy.request(url)
cy.request(url, body)
cy.request(method, url)
cy.request(method, url, body)
cy.request(options)
Enter fullscreen mode Exit fullscreen mode

أبسط مثال هو طلب GET:

cy.request('https://jsonplaceholder.typicode.com/users')
Enter fullscreen mode Exit fullscreen mode

لأي طلب يحتاج إلى طريقة، رؤوس، أو جسم، استخدم كائن الخيارات:

cy.request({
  method: 'POST',
  url: 'https://jsonplaceholder.typicode.com/posts',
  headers: {
    'Content-Type': 'application/json'
  },
  body: {
    title: 'API test',
    body: 'created from Cypress',
    userId: 1
  }
})
Enter fullscreen mode Exit fullscreen mode

أهم الخيارات:

  • method: فعل HTTP مثل GET, POST, PUT, PATCH, DELETE. الافتراضي هو GET.
  • url: نقطة النهاية المطلوبة.
  • body: حمولة الطلب. يحول Cypress الكائنات إلى JSON.
  • headers: رؤوس الطلب.
  • auth: بيانات المصادقة الأساسية HTTP Basic Auth.
  • qs: معلمات query string ككائن.
  • failOnStatusCode: اجعله false عندما تريد اختبار استجابات 4xx أو 5xx.

مثال على اختبار استجابة فشل متوقعة:

cy.request({
  method: 'GET',
  url: 'https://jsonplaceholder.typicode.com/users/99999',
  failOnStatusCode: false
}).then((response) => {
  expect(response.status).to.eq(404)
})
Enter fullscreen mode Exit fullscreen mode

بدون failOnStatusCode: false سيفشل الاختبار تلقائيًا عند أي حالة ليست 2xx أو 3xx.

التأكد من الحالة والجسم

يعيد cy.request() كائن استجابة. استخدم .then() للوصول إليه.

أهم الخصائص:

  • status: رمز حالة HTTP.
  • body: جسم الاستجابة. إذا كان Content-Type هو JSON، يقوم Cypress بتحليله إلى كائن JavaScript.
  • headers: رؤوس الاستجابة.
  • duration: مدة الطلب بالمللي ثانية.

مثال كامل:

describe('Users API', () => {
  it('returns a list of users', () => {
    cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
      expect(response.status).to.eq(200)
      expect(response.body).to.be.an('array')
      expect(response.body).to.have.length(10)
      expect(response.body[0]).to.have.property('email')
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

بما أن response.body كائن JavaScript، يمكنك استخدام تأكيدات Chai المعتادة:

expect(response.body[0].address).to.have.property('city')
expect(response.body[0].company.name).to.be.a('string')
Enter fullscreen mode Exit fullscreen mode

يمكنك أيضًا فحص الرؤوس:

cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
  expect(response.headers['content-type']).to.include('application/json')
})
Enter fullscreen mode Exit fullscreen mode

للمزيد حول تنظيم هذه الفحوصات، راجع تأكيدات API وأفضل ممارسات اختبار API.

ربط الطلبات وإعادة استخدام رمز المصادقة

في واجهات API الحقيقية، غالبًا تحتاج إلى تسجيل الدخول أولًا، ثم استخدام الرمز المميز في الطلبات التالية.

النمط العملي:

  1. أرسل طلب تسجيل الدخول.
  2. اقرأ token من الاستجابة.
  3. أرسله في ترويسة Authorization.
describe('Authenticated API flow', () => {
  it('logs in and fetches a protected resource', () => {
    cy.request({
      method: 'POST',
      url: 'https://api.example.com/login',
      body: {
        email: 'user@example.com',
        password: 'secret'
      }
    }).then((loginResponse) => {
      expect(loginResponse.status).to.eq(200)

      const token = loginResponse.body.token

      cy.request({
        method: 'GET',
        url: 'https://api.example.com/profile',
        headers: {
          Authorization: `Bearer ${token}`
        }
      }).then((profileResponse) => {
        expect(profileResponse.status).to.eq(200)
        expect(profileResponse.body).to.have.property('email', 'user@example.com')
      })
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

إذا احتاجت عدة اختبارات إلى نفس الرمز، انقل تسجيل الدخول إلى beforeEach أو أمر مخصص:

beforeEach(() => {
  cy.request({
    method: 'POST',
    url: 'https://api.example.com/login',
    body: {
      email: 'user@example.com',
      password: 'secret'
    }
  }).then((response) => {
    Cypress.env('token', response.body.token)
  })
})
Enter fullscreen mode Exit fullscreen mode

ثم استخدمه في الاختبار:

cy.request({
  method: 'GET',
  url: 'https://api.example.com/profile',
  headers: {
    Authorization: `Bearer ${Cypress.env('token')}`
  }
})
Enter fullscreen mode Exit fullscreen mode

هذا النمط هو نفس ما تستخدمه في اختبار تكامل API، حيث يغذي طلب نتيجة الطلب التالي.

استخدام cy.intercept() للتزييف

يرسل cy.request() طلبًا حقيقيًا إلى API. أما cy.intercept() فيعترض الطلبات التي يرسلها تطبيق الواجهة الأمامية من المتصفح.

الفرق المهم:

  • cy.request() لا يمر عبر المتصفح.
  • cy.intercept() يعترض فقط طلبات المتصفح.
  • لذلك لا يمكن لـ cy.intercept() اعتراض cy.request().

استخدم cy.intercept() عندما تريد اختبار كيف تتصرف الواجهة مع استجابة معينة، مثل خطأ خادم أو قائمة فارغة.

مثال تزييف استجابة:

cy.intercept('GET', '/api/users', {
  statusCode: 200,
  body: [{ id: 1, name: 'Ada' }]
})
Enter fullscreen mode Exit fullscreen mode

أي طلب من المتصفح إلى /api/users سيحصل على هذه الاستجابة الثابتة.

مثال لاختبار معالجة الخطأ:

it('shows an error banner when the API fails', () => {
  cy.intercept('GET', '/api/users', {
    statusCode: 500,
    body: { message: 'Server error' }
  }).as('getUsers')

  cy.visit('/dashboard')

  cy.wait('@getUsers')
    .its('response.statusCode')
    .should('eq', 500)

  cy.contains('Something went wrong').should('be.visible')
})
Enter fullscreen mode Exit fullscreen mode

ضع cy.intercept() قبل الإجراء الذي يطلق الطلب، مثل cy.visit() أو الضغط على زر. إذا عرّفته بعد الطلب، فلن يلتقط شيئًا.

إذا كنت تقارن بين تزييف استجابة واحدة ومحاكاة خدمة API كاملة، راجع المحاكاة الوهمية لواجهة برمجة التطبيقات والتزييف مقابل المحاكاة الوهمية لواجهة برمجة التطبيقات.

متى يكون Cypress مناسبًا لاختبار API

استخدم Cypress لاختبار API عندما تكون الفحوصات مرتبطة باختبارات المتصفح:

  • تجهيز بيانات قبل اختبار UI.
  • تسجيل الدخول عبر API لتجاوز شاشة تسجيل الدخول.
  • التحقق من نقطة نهاية تعتمد عليها الواجهة.
  • تزييف استجابة API لاختبار حالة خطأ في الواجهة.
  • تشغيل مجموعة صغيرة من smoke tests إذا كان Cypress هو مشغل الاختبارات الوحيد لديك.

في هذه الحالات، cy.request() وcy.intercept() يبقيان كل شيء داخل نفس مشروع الاختبار.

متى تحتاج إلى أداة API متخصصة

يصبح Cypress أقل ملاءمة عندما تبني مجموعة اختبار API كبيرة ومستقلة.

المشكلات التي تظهر غالبًا:

  • لا يوجد منشئ طلبات مرئي؛ كل طلب يُكتب ككود.
  • إدارة الرؤوس، الأجسام، والبيئات يدويًا تصبح مرهقة مع مئات النقاط.
  • Cypress يشغل سياق متصفح حتى في اختبارات API البحتة.
  • تعريفات API تعيش داخل ملفات الاختبار بدل مواصفات مشتركة للفريق.

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

لتشغيل سيناريوهات الاختبار في CI، يمكنك استخدام Apidog CLI:

npm install -g apidog-cli

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t  \
  -e  \
  -r cli,html,junit
Enter fullscreen mode Exit fullscreen mode

المعاني الأساسية:

  • -t: يحدد سيناريو أو مجموعة اختبار محفوظة.
  • -e: يحدد البيئة.
  • -r: يحدد تنسيقات التقارير مثل cli, html, json, junit.
  • -d أو --iteration-data: لتشغيل الاختبار باستخدام ملف بيانات.
  • --upload-report: لرفع النتائج مرة أخرى إلى مساحة العمل.

طريقة التفكير العملية:

  • استخدم cy.request() عندما يدعم اختبار API اختبارات المتصفح.
  • استخدم أداة API متخصصة عندما يصبح اختبار API هو المهمة الرئيسية.

إذا كنت تقارن الأدوات، راجع أدوات أتمتة اختبار API التي تعمل في CI/CD وأفضل 30 أداة لاختبار API.

الأسئلة الشائعة

هل يتم تشغيل cy.request() في المتصفح؟

لا. يتم تشغيل cy.request() من عملية Cypress Node خارج المتصفح. لذلك لا يتأثر بـ CORS أو سياسة نفس المصدر، ولا يمكن لـ cy.intercept() اعتراضه.

كيف أختبر استجابة 400 أو 404 دون فشل الاختبار؟

استخدم failOnStatusCode: false، ثم تحقق من الحالة بنفسك:

cy.request({
  url: '/api/users/unknown',
  failOnStatusCode: false
}).then((response) => {
  expect(response.status).to.eq(404)
})
Enter fullscreen mode Exit fullscreen mode

هل يمكنني استخدام cy.request() لتسجيل الدخول قبل اختبار واجهة المستخدم؟

نعم. أرسل طلب POST إلى نقطة تسجيل الدخول، اقرأ الرمز من response.body، ثم خزّنه في Cypress.env() أو localStorage أو cookie حسب طريقة مصادقة تطبيقك. هذا يختصر خطوات واجهة المستخدم ويسرّع الاختبارات.

ما الفرق بين cy.request() وcy.intercept()؟

cy.request() يرسل طلب HTTP حقيقي ويعيد الاستجابة الفعلية. استخدمه لاختبار API مباشرة.

cy.intercept() يراقب أو يزيف الطلبات التي ترسلها الواجهة من المتصفح. استخدمه لاختبار سلوك الواجهة مع استجابات API مختلفة.

هل أستخدم Cypress أم أداة مخصصة لاختبار API؟

استخدم Cypress عندما تكون اختبارات API جزءًا من مجموعة اختبارات المتصفح. أما إذا كنت تبني مجموعة API مستقلة، أو تحتاج إلى تشغيل CI مخصص، أو تريد تعريفات API مشتركة للفريق، فاستخدم أداة متخصصة مثل Apidog. راجع أفضل ممارسات اختبار API لتحديد النهج الأنسب.

Top comments (0)