يا جماعة الخير، كيف حالكم؟ معكم أبو عمر. اسمحوا لي اليوم أن أرجع بالزمن قليلاً، لأيام كان فيها فنجان القهوة الصباحي لا يكتمل إلا بجرعة من القلق والتوتر قبل أي عملية نشر (Deployment) جديدة. سأحكي لكم قصة قصيرة، لكنها غيرت طريقة تفكير فريقي بأكمله.
كنا نعمل على مشروع ضخم، وفي ليلة من الليالي، قرابة الساعة الواحدة صباحًا، كان علينا إطلاق تحديث “بسيط”. نعم، الكلمة التي يخشاها كل مبرمج. التحديث كان عبارة عن تعديل في تصميم زر واحد في صفحة الملف الشخصي للمستخدم. زميلي “سامر”، وهو من أشطر المطورين الذين عرفتهم، أجرى التعديل، واختبره على شاشته الكبيرة والمرتبة، وبدا كل شيء مثالياً. قال بثقة: “تمام يا أبو عمر، جاهز للنشر”.ه>
ضغطنا على زر النشر ونحن نحلم بالعودة إلى فراشنا. بعد دقائق، بدأت تصلنا رسائل غاضبة من فريق الدعم الفني. لوحة التحكم الرئيسية للمستخدمين (Dashboard)، وهي قلب التطبيق، أصبحت في حالة فوضى عارمة. الأعمدة متداخلة، والرسوم البيانية خارج إطاراتها، والقوائم الجانبية تختفي وتظهر كالأشباح. كارثة بكل معنى الكلمة.
قضينا الساعات الثلاث التالية في عملية “إطفاء حرائق” محمومة، ونحن نشرب كاسات الشاي بالنعناع واحدة تلو الأخرى، لنكتشف في النهاية أن تعديل CSS “البسيط” الذي أجراه سامر على الزر، أثّر بشكل غير متوقع على بعض الأنماط العامة (Global Styles) التي تستخدمها لوحة التحكم. الجملة التي ترددت في تلك الليلة كانت، بالطبع، “والله يا عمي، لقد بدت أفضل على جهازي!”.
تلك الليلة كانت نقطة التحول. أدركنا أن الاعتماد على العين البشرية وحدها في عالم الواجهات الأمامية المعقد اليوم هو ضرب من الجنون. ومن هنا بدأت رحلتنا مع ما أسميه “شبكة الأمان للمطورين”: الاختبار البصري التراجعي.
ما هو الاختبار البصري التراجعي (Visual Regression Testing)؟
ببساطة شديدة، هو عملية أتمتة “لعبة الفروقات” التي كنا نلعبها في طفولتنا. الفكرة هي أن نلتقط “صوراً” أو “لقطات شاشة” لواجهات المستخدم الخاصة بنا في حالة مستقرة ومعروفة (نسميها الخط الأساسي – Baseline)، وبعد أي تعديل جديد على الكود، نلتقط لقطات جديدة (نسميها المرشح – Candidate)، ثم نستخدم أداة لمقارنة اللقطات الجديدة بالقديمة بكسل ببكسل.
إذا لم يكن هناك أي اختلاف، فهذا يعني أن تغييرك لم “يكسر” أي شيء بصرياً. أما إذا كان هناك اختلاف، فإن الأداة تولّد صورة ثالثة (نسميها الفرق – Diff) تسلط الضوء على الأجزاء التي تغيرت باللون الأحمر، لتقرر أنت كـ”حكم” ما إذا كان هذا التغيير مقصودًا أم أنه خطأ كارثي.

مخطط يوضح آلية عمل الاختبار البصري التراجعي
لماذا هو بهذه الأهمية؟
- يكشف الأخطاء الصامتة: العديد من الأخطاء البصرية لا تؤدي إلى انهيار التطبيق أو ظهور خطأ في الكونسول. قد يكون مجرد عنصر مزاح ببضعة بكسلات، أو لون خط مختلف قليلاً، أو تداخل عنصرين في شاشة بحجم معين. هذه الأخطاء تدمر تجربة المستخدم بصمت.
- يعطي ثقة بالنشر: بدلاً من الخوف من كل تعديل CSS، يصبح لديك شبكة أمان تخبرك على الفور إذا كان تعديلك قد أثر على جزء آخر من التطبيق لم تفكر فيه حتى.
- يوفر الوقت والجهد: تخيل أنك لست بحاجة إلى فتح 20 صفحة مختلفة على 3 متصفحات و 4 أحجام شاشة مختلفة بعد كل تغيير. الأتمتة تقوم بهذا العمل الشاق بدلاً عنك.
- يُنهي جدل “تعمل على جهازي”: الدليل الآن ليس رأيًا، بل صورة “Diff” واضحة تظهر المشكلة للجميع. لا مجال للمجادلة.
كيف نبدأ؟ الأدوات والخطوات العملية
هناك العديد من الأدوات الرائعة في هذا المجال، بعضها خدمات مدفوعة مثل Percy و Chromatic (وهي ممتازة للمشاريع الكبيرة والفرق)، وبعضها مفتوح المصدر يمكنك استضافته بنفسك مثل BackstopJS و Playwright.
دعونا نأخذ مثالاً عملياً باستخدام BackstopJS، لأنها أداة رائعة ومجانية للبدء.
مثال عملي مع BackstopJS
لنفترض أن لدينا موقعاً بسيطاً ونريد التأكد من أن الصفحة الرئيسية وصفحة “من نحن” لا تتغيران بشكل غير متوقع.
1. التثبيت والإعداد:
أولاً، ستحتاج إلى تثبيت الأداة في مشروعك:
npm install -g backstopjs
# داخل مجلد مشروعك
backstopjs init
سيؤدي هذا إلى إنشاء ملف تكوين افتراضي اسمه backstop.json. هذا هو قلب الأداة وعقلها المدبر.
2. ضبط ملف التكوين:
سنقوم بتعديل ملف backstop.json ليشمل السيناريوهات التي نريد اختبارها. الملف يبدو شيئاً كهذا:
{
"id": "my_awesome_project",
"viewports": [
{
"label": "phone",
"width": 320,
"height": 480
},
{
"label": "tablet",
"width": 1024,
"height": 768
},
{
"label": "desktop",
"width": 1920,
"height": 1080
}
],
"onBeforeScript": "playwright/onBefore.js",
"onReadyScript": "playwright/onReady.js",
"scenarios": [
{
"label": "Homepage",
"url": "http://localhost:3000",
"selectors": ["document"],
"misMatchThreshold": 0.1
},
{
"label": "About Us Page",
"url": "http://localhost:3000/about",
"selectors": ["document"],
"delay": 500
},
{
"label": "Login Modal",
"url": "http://localhost:3000",
"clickSelector": "#login-button",
"postInteractionWait": 1000,
"selectors": ["#login-modal"]
}
],
"paths": {
"bitmaps_reference": "backstop_data/bitmaps_reference",
"bitmaps_test": "backstop_data/bitmaps_test",
"engine_scripts": "backstop_data/engine_scripts",
"html_report": "backstop_data/html_report",
"ci_report": "backstop_data/ci_report"
},
"report": ["browser"],
"engine": "playwright",
"engineOptions": {
"browser": "chromium",
"args": ["--no-sandbox"]
},
"asyncCaptureLimit": 5,
"asyncCompareLimit": 50,
"debug": false,
"debugWindow": false
}
شرح سريع للكود:
viewports: نحدد هنا أحجام الشاشات التي نريد الاختبار عليها (هاتف، جهاز لوحي، سطح مكتب).scenarios: هذه هي قائمة الاختبارات. لكل سيناريو نحدد:
label: اسم وصفي للاختبار.url: الرابط الذي سيتم اختباره.selectors: يمكننا تحديد جزء معين من الصفحة لاختباره (مثل#main-header) أو الصفحة بأكملها (document).clickSelector/postInteractionWait: يمكننا محاكاة تفاعل المستخدم، مثل النقر على زر لفتح نافذة منبثقة، ثم الانتظار قليلاً قبل التقاط الصورة.engine: نحدد هنا محرك المتصفح الذي سيستخدم لالتقاط الصور. Playwright خيار حديث وقوي.
3. إنشاء الخط الأساسي (Baseline):
الآن، والتطبيق في حالته المستقرة، نقوم بتشغيل الأمر التالي لإنشاء لقطات الشاشة المرجعية:
backstopjs reference
سيقوم BackstopJS بزيارة العناوين المحددة في السيناريوهات، والتقاط صور لها بكل أحجام الشاشات، وحفظها كـ “النسخة الذهبية” أو الخط الأساسي.
4. إجراء الاختبار بعد التعديل:
الآن، اذهب وقم بتعديل CSS الذي تريده. بعد الانتهاء، بدلاً من القلق، قم بتشغيل الأمر التالي:
backstopjs test
سيقوم BackstopJS بالتقاط صور جديدة ومقارنتها بالصور المرجعية. بعد الانتهاء، سيفتح لك تقريراً تفصيلياً في المتصفح. إذا كان هناك أي اختلاف، سترى الصور الثلاث: المرجعية، الجديدة، وصورة الفروقات التي لا تكذب ولا تتجمل!
5. المراجعة والموافقة:
إذا كان التغيير مقصوداً (مثلاً، غيرت لون زر عمداً)، يمكنك إخبار BackstopJS بقبول التغييرات الجديدة كخط أساسي جديد عبر الأمر:
backstopjs approve
وهكذا، تصبح النسخة الجديدة هي المرجع للمستقبل.
نصائح أبو عمر الذهبية ✨
بعد سنوات من استخدام هذه التقنية، اسمحوا لي أن أقدم لكم بعض النصائح من القلب:
- ابدأ صغيراً ولكن مهماً: لا تحاول اختبار كل بكسل في موقعك من اليوم الأول. ابدأ بالصفحات والمكونات الأكثر أهمية: الصفحة الرئيسية، صفحة المنتج، عملية الدفع، لوحة التحكم.
- تجاهل المحتوى الديناميكي: تطبيقك قد يعرض بيانات متغيرة مثل “آخر زيارة كانت قبل 5 دقائق” أو إعلانات عشوائية. هذا سيؤدي إلى فشل الاختبارات دائماً. معظم الأدوات تسمح لك بإخفاء عناصر معينة (
hideSelectors) أو استبدالها بمحتوى ثابت قبل التقاط الصورة. - أتمتة الأتمتة (CI/CD): القوة الحقيقية تكمن في دمج هذه الاختبارات مع سير عملك (CI/CD Pipeline). اجعل الاختبارات البصرية تعمل تلقائياً مع كل Pull Request. إذا فشل الاختبار، يتم منع الدمج (Merge) حتى يتم حل المشكلة. هذا يضمن عدم وصول أي خطأ بصري إلى الكود الرئيسي.
- إدارة الخط الأساسي بحكمة: تحديث الخط الأساسي (
approve) يجب أن يكون قراراً واعياً من الفريق، وليس مجرد نقرة زر للتخلص من “الفشل”. تأكد من أن كل تغيير تمت الموافقة عليه هو تغيير مقصود ومطلوب.
الخلاصة: من الفوضى إلى الثقة
التحول من الاعتماد على الاختبار اليدوي المجهد والممل إلى نظام آلي للاختبار البصري التراجعي كان واحداً من أفضل القرارات التقنية التي اتخذناها. لقد حول عملية نشر التحديثات من مغامرة مرعبة إلى عملية روتينية يمكن التنبؤ بها.
لم نعد نسمع جملة “لقد بدت أفضل على جهازي” كعذر، بل أصبحنا نراها كمزحة تذكرنا بالأيام الخوالي. الاستثمار في جودة الواجهة الأمامية ليس رفاهية، بل هو أساس لبناء ثقة المستخدم وولائه. لا تنتظروا كارثة منتصف الليل لتبدأوا. ابدأوا اليوم، ولو بخطوة صغيرة، وستنامون بهدوء أكبر في ليالي النشر القادمة. 👍