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

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

INEZA Felin-Michel

INEZA Felin-Michel

7 يوليو 2026

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

Apidog للمؤسسات

النشر على الخوادم المحلية

SSO و RBAC

متوافق مع SOC 2

استكشف Apidog للمؤسسات

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

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

زر

لماذا تختبر واجهات برمجة التطبيقات (APIs) باستخدام Cypress

تدير معظم مجموعات اختبار Cypress متصفحًا. ولكن الكثير مما تتحقق منه في واجهة المستخدم هو في الواقع واجهة برمجة التطبيقات الأساسية: هل يعيد /login رمزًا مميزًا، هل يعيد /users الشكل الصحيح للبيانات، هل ينشئ طلب POST السجل الذي تتوقعه.

اختبار نقاط النهاية هذه مباشرة له فائدتان. أولاً، تعمل فحوصات API بشكل أسرع من تدفقات واجهة المستخدم لأنه لا يوجد عرض ولا انتظار للعناصر. ثانيًا، يمكنك استخدام cy.request() لإعداد بيانات الاختبار. فبدلاً من النقر عبر نموذج التسجيل لإنشاء مستخدم، يمكنك إرسال طلب 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)

أبسط استدعاء يمرر عنوان URL. بدون تحديد طريقة، يستخدم Cypress الطريقة الافتراضية GET:

cy.request('https://jsonplaceholder.typicode.com/users')

لأي شيء يتجاوز طلب GET الأساسي، قم بتمرير كائن خيارات. يمنحك هذا تحكمًا كاملاً في الطريقة، النص الأساسي، والرؤوس:

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
  }
})

خيارات مفيدة في هذا الكائن:

هذا الخيار الأخير مهم للاختبارات السلبية. بشكل افتراضي، يفشل cy.request() الاختبار عند أي حالة غير 2xx أو 3xx. إذا كنت تتحقق من أن طلبًا سيئًا يعيد 400، فيجب عليك إلغاء الاشتراك:

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

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

يعيد cy.request() كائن استجابة. قم بربط .then() لقراءته. تحتوي الاستجابة على أربعة خصائص ستستخدمها غالبًا:

إليك اختبار كامل يتحقق من الحالة، شكل النص الأساسي، وحقل معين:

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')
    })
  })
})

نظرًا لأن response.body هو بالفعل كائن محلل، يمكنك التأكد منه باستخدام Chai القياسي. يمكنك التحقق من النوع، الطول، الخصائص المتداخلة، أو القيم الدقيقة. هذه هي نفس صيغة التأكيد التي تستخدمها لاختبارات واجهة المستخدم، لذا لا يوجد شيء جديد لتعلمه.

يمكنك أيضًا التأكد من رؤوس الاستجابة، وهو أمر مفيد للتحقق من نوع المحتوى أو التخزين المؤقت:

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

لإلقاء نظرة أعمق على هيكلة هذه الفحوصات، راجع دليلنا حول تأكيدات API والممارسات الأوسع لـ أفضل ممارسات اختبار API.

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

تحتاج واجهات برمجة التطبيقات الحقيقية إلى مصادقة. النمط الشائع هو تسجيل الدخول مرة واحدة، الحصول على الرمز المميز، ثم إرساله مع كل طلب يليه. cy.request() يربط الطلبات بشكل نظيف لهذا الغرض.

أرسل طلب تسجيل الدخول، اقرأ الرمز المميز من نص الاستجابة، ثم استخدمه في الاستدعاء التالي:

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')
      })
    })
  })
})
```

إذا كانت عدة اختبارات تحتاج إلى نفس الرمز المميز، انقل عملية تسجيل الدخول إلى beforeEach وقم بتخزين الرمز المميز باستخدام Cypress.env() أو اسم مستعار مغلف بحيث يلتقطه كل اختبار. هذا يحافظ على إعداد المصادقة في مكان واحد بدلاً من تكراره في كل مواصفة.

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

cy.intercept() للتزييف (stubbing)

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

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

يمكنك التجسس على طلب، أو تزييفه باستجابة ثابتة، أو انتظاره. للتزييف، مرر كائن استجابة:

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

الآن، أي طلب من المتصفح إلى /api/users سيعيد تلك الحمولة الثابتة. يتيح لك هذا اختبار الحالات الهامشية التي يصعب تفعيلها ضد خلفية حية، مثل قائمة فارغة، خطأ 500، أو استجابة بطيئة.

للتأكد من حدوث الطلب، قم بتسميته بـ .as() وانتظره:

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')
})

يتوقف السطر cy.wait('@getUsers') عن تنفيذ الاختبار حتى يتم حل الطلب المعترض، ثم يسلمك الطلب والاستجابة للتأكيد عليها. قم بإعداد الاعتراض قبل الإجراء الذي يؤدي إلى الطلب، وإلا فلن يلتقط أي شيء. إذا كنت تفكر في متى تزيف استجابة مقابل محاكاة خدمة كاملة، فإن منشوراتنا حول المحاكاة الوهمية لواجهة برمجة التطبيقات (API mocking) والتزييف مقابل المحاكاة الوهمية لواجهة برمجة التطبيقات (API stubbing vs API mocking) توضح المفاضلات.

متى يكون Cypress لاختبار واجهات برمجة التطبيقات منطقيًا، ومتى لا يكون كذلك

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

كما أنه مناسب لمجموعة قليلة من اختبارات فحص سريعة (smoke tests) لواجهة برمجة التطبيقات المستقلة عندما يكون Cypress هو مشغل الاختبار الوحيد لديك ولا ترغب في إضافة تبعية أخرى.

حيث يصبح الأمر محرجًا هو مجموعة اختبار واجهة برمجة تطبيقات كبيرة ومستقلة. لقد تم بناء Cypress للمتصفح، لذا فإن اختبار واجهة برمجة التطبيقات هو قدرة مضافة فوقه، وليس التصميم الأساسي. تظهر بعض الثغرات مع نمو المجموعة:

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

بالنسبة لـ CI، يقوم سطر أوامر Apidog CLI بتشغيل سيناريوهات الاختبار المحفوظة بدون واجهة رسومية في أي خطوة يمكنها تشغيل Node:

npm install -g apidog-cli

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

تستهدف العلامة -t سيناريو أو مجموعة اختبار محفوظة، وتحدد -e بيئة، وتختار -r تنسيقات التقارير (cli, html, json, junit). يتصل مخرج JUnit مباشرة بمعظم لوحات معلومات CI. أضف -d أو --iteration-data لتشغيل اختبار من ملف بيانات، و --upload-report لدفع النتائج مرة أخرى إلى مساحة العمل الخاصة بك. يقوم سطر الأوامر (CLI) بتشغيل السيناريوهات المحفوظة؛ إنه ليس مرسل طلبات تفاعلي.

طريقة مفيدة للتفكير في الأمر: استخدم cy.request() لفحوصات واجهة برمجة التطبيقات التي تدعم اختبارات المتصفح الخاصة بك، وتوجه إلى أداة متخصصة في واجهة برمجة التطبيقات عندما يكون اختبار واجهة برمجة التطبيقات هو المهمة الرئيسية. إذا كنت تقارن الخيارات، فإن ملخصاتنا لأدوات أتمتة اختبار API التي تعمل في CI/CD وأفضل 30 أداة لاختبار API تغطي المجال.

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

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

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

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

بشكل افتراضي، يفشل cy.request() عند أي حالة غير 2xx أو 3xx. اضبط failOnStatusCode: false في كائن الخيارات، ثم قم بالتأكد من الحالة بنفسك باستخدام expect(response.status).to.eq(404).

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

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

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

يرسل cy.request() طلب HTTP حقيقي ويعيد الاستجابة الفعلية، لذلك تستخدمه لاختبار واجهة برمجة تطبيقات. بينما cy.intercept() يراقب أو يزيف الطلبات التي يقوم بها الواجهة الأمامية في المتصفح، لذلك تستخدمه للتحكم فيما تتلقاه واجهة المستخدم الخاصة بك. الأول يضرب الشبكة؛ والآخر يشكلها.

هل يجب أن أستخدم Cypress أم أداة مخصصة لاختبار واجهة برمجة التطبيقات؟

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

ممارسة تصميم API في Apidog

اكتشف طريقة أسهل لبناء واستخدام واجهات برمجة التطبيقات