بيئة الاختبار

وحسب ما ورد في قسم ما هو الاختبار، إنّ الاختبارات في JavaScript هي في الأساس رموز برمجية نتأكّد من إجرائها بنجاح، أي بدون عرض Error. مع ذلك، تتمثل إحدى طرق التبسيط في تبسيط هذا التعريف لأنّه لا يأخذ في الاعتبار مكان تشغيل الرمز، أي بيئة الاختبار الخاصة به.

يمكن النظر إلى بيئة الاختبار على نطاق واسع على أنّها مكوّنَين: بيئة وقت التشغيل التي تستخدمها لإجراء الاختبار (مثل Node أو المتصفح) بالإضافة إلى واجهات برمجة التطبيقات المتاحة لك.

بيئة وقت التشغيل

تهدف أوقات التشغيل مثل Node أو الأدوات المماثلة مثل Deno أو Bun إلى دعم رمز JS من جهة الخادم أو للأغراض العامة. ولا تشتمل بيئاتها على واجهات برمجة تطبيقات قد تتوقعها في المتصفح، مثل إنشاء عناصر DOM وHTML والعمل عليها أو أي مفهوم للمكوِّن المرئي أو هدف العرض (أي ليس العناصر فقط، بل عرض هذه العناصر مرئيًا باستخدام CSS في إطار عرض).

وبالتالي، لن تنجح أوقات التشغيل المخصّصة للأغراض العامة هذه إذا حاولت، على سبيل المثال عرض عناصر React حتى يمكن اختبارها، لعدم توفّر كائنات document أو window.

من ناحية أخرى، إذا أجريت الاختبارات داخل متصفّح، قد لا تتوفّر واجهات برمجة التطبيقات (API) المضمَّنة التي يمكنك توقّعها من أوقات التشغيل هذه بدون استخدام رمز polyfill أو إجراء بعض الإجراءات الإضافية. تُشبه آلة العُطل الشائعة قراءة الملفات وكتابتها، إذ لا يمكن إدخال import { fs } from 'node:'fs'; داخل متصفّح وقراءة ملف بهذه الطريقة كجزء من الاختبار.

تعد مشكلة واجهة برمجة التطبيقات "الويب" مقابل "الخلفية" هذه خارج نطاق الاختبار فقط، لأنه قد يكون من المحرج أن يكون لديك قاعدة رموز مع كل من الخادم وأجزاء العميل، لكنها ترتبط بفكرة كتابة تعليمات برمجية قابلة للاختبار، والتي سنعيد النظر فيها خلال هذه الدورة التدريبية.

اختبار منطق الخوارزمية أو النشاط التجاري

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

كمثال سريع، قد يكون لديك دالة عقدة تقرأ ملفًا وتكتبه من القرص، وتعدّله في العملية. من خلال إعادة تنظيم الدالة لقبول الدوال التي تؤدي القراءة والكتابة من القرص، جعلتها قابلة للاختبار في أي مكان.

في هذه الحالة، يمكنك استخدام أي بيئة لاختبار هذا الرمز، إما في وقت التشغيل من جهة الخادم أو في المتصفح. في اختبارك، يمكنك توفير المساعدين الذين يخزنون ملفًا افتراضيًا في الذاكرة أو تعرض بيانات العنصر النائب. لا بأس في تقديم هذا النوع من المساعدات في الاختبار، لأنه ليس من المهم التحقق، على سبيل المثال، من أنّ fs.writeFileSync تعمل. ركز على التعليمة البرمجية وما الذي يجعلها فريدة أو خطيرة.

محاكاة واجهات برمجة التطبيقات للمتصفِّح

تمنحك العديد من إطارات عمل الاختبار، مثل Vitest، خيارًا لمحاكاة بيئة واجهة برمجة التطبيقات للمتصفّح بدون تشغيل متصفّح. يستخدم Vitest داخليًا مكتبة تسمى JSDOM. يمكن أن يكون هذا اختيارًا جيدًا لاختبارات المكونات البسيطة حيث يكون النفقات العامة لاستخدام المتصفح مرتفعًا.

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

مرة أخرى، قد يكون هذا الخيار مناسبًا لاختبار المكوّنات، حيث يمثل المكوِّن أحد عناصر التفاعل أو مكوّن الويب، وغير ذلك. عادةً ما تنشئ هذه الأنواع من المكوّنات نموذج كائن المستند وتتفاعل معه بطريقة صغيرة نسبيًا، ويمكن أن يوفر المتصفح في وضع المحاكاة وظائف كافية للتأكد من عمل المكوّن بالطريقة التي تريدها. يتضمن قسم قادم مثالاً لاختبار مكون React باستخدام Vitest وJSDOM.

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

التحكم في متصفح فعلي

لاختبار الرمز البرمجي وفقًا لتجربة المستخدمين، يكون استخدام متصفّح حقيقي هو الخيار الأفضل. من الناحية العملية، سيبدأ اختبار أوقات التشغيل التي تدعم المتصفح والتحكم في مثيلات متصفح حقيقي، حتى إذا تم تشغيلها "start" داخل Node.js.

ويعني التحكّم في المتصفّح كجزء من الاختبار أنّه سيتم فتحه تمامًا كما لو كان بإمكان المستخدم، ما يسمح للاختبار بالتحكّم فيه من خلال تحميل عناوين URL أو تحميل محتوى HTML وJavaScript مخصّص أو أي شيء مطلوب لإجراء الاختبار. يمكنك بعد ذلك كتابة التعليمات البرمجية لتعمل كمستخدم، مثل التحكم في الماوس، أو كتابة الإدخال في مربعات الإدخال.

يمكن للأدوات الحديثة، مثل WebdriverIO أو Web Test Runner، التحكّم في جميع المتصفِّحات الرئيسية، وتشغيل مثيلات متعددة في الوقت نفسه. يمكن أن تعمل هذه المتصفّحات إلى جانب برنامج الاختبار (على سبيل المثال، على جهاز الكمبيوتر الخاص بك أو كجزء من إجراء CI) أو يتم تكليفها بمصادر خارجية لخدمات تجارية خارجية ستديرها نيابةً عنك.

غالبًا ما يكون لدى مكتبات الاختبار الأكثر انتشارًا (بما في ذلك Vitest وJest) وضع المتصفّح، ولكن لأنّ أوضاع المتصفّح مصدرها Node.js، فغالبًا ما تكون أوضاع المتصفّح "مثبّتة" وتفتقد إلى ميزات مفيدة. على سبيل المثال، لا يمكن لـ Vitest استيراد وحدة في المتصفح، وهي إحدى المبادئ الأساسية الفعّالة التي نستخدمها في المثال على الصفحة التالية.

التطبيق العملي

مع زيادة مستوى تعقيد اختباراتك، يصبح استخدام متصفّح حقيقي أكثر أهمية.

  • في الاختبارات التي لا تستخدم أي ميزات أو حد أدنى من الميزات في DOM، حتى الميزات المتوفّرة في Node.js وأوقات التشغيل المشابهة، مثل fetch أو EventTarget، لا يهمّ البيئة.
  • بالنسبة إلى اختبارات المكونات الصغيرة، يمكن أن يكون JSDOM مناسبًا.
  • من المنطقي إجراء اختبارات أوسع نطاقًا، مثل الاختبارات الشاملة، التي يمكنها محاكاة تسجيل دخول المستخدم وتنفيذ إجراء أساسي، بشكلٍ كامل في متصفّح حقيقي.

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

التحقق من فهمك

ما ميزات المتصفح التي *لا* تدعمها طبقة المحاكاة؟

محرك التخطيط.
بما أنّ JSDOM ليست أداة مرئية، لا يمكن استخدامها للتحقق من موضع العنصر على الصفحة أو سمات CSS التي تم حلّها أو أي أجزاء أخرى من تنسيق الموقع الإلكتروني.
WebSocket
يشتمل JSDOM على polyfill WebSocket، لذلك فإن الرمز الذي تستخدمه سيعمل.
requestAnimationFrame
باستخدام العلامة "pretendToBeVisual"، يستدعي jsdom استدعاء "الرسوم المتحركة" بمعدّل 60 لقطة في الثانية، حتى لو لم يتم رسم أي شيء في الواقع.