الاختبار البصري التراجعي: كيف تخلصنا من كابوس “لم يكن شكله هكذا بالأمس”؟

يا جماعة الخير، السلام عليكم. معكم أبو عمر.

اسمحوا لي أن أروي لكم قصة قصيرة حدثت معي ومع فريقي قبل بضع سنوات، قصة أظن أن الكثير من المطورين، خاصة في مجال الواجهات الأمامية (Frontend)، قد عاشوا فصلاً من فصولها. كنا نعمل على مشروع كبير، بوابة إلكترونية ضخمة، وكنا على وشك إطلاق نسخة جديدة ومهمة. الأدرينالين كان في أعلى مستوياته، والقهوة لا تفارق مكاتبنا.

في ليلة ما قبل الإطلاق بيومين، قام أحد المطورين الجدد في الفريق بإجراء تعديل بسيط جداً. كان المطلوب منه تغيير تصميم الأزرار الرئيسية في الموقع لتصبح أكثر حداثة. تغيير بسيط في ملف CSS عام، شيء مثل تعديل الـ padding والـ border-radius. كل الاختبارات الآلية (Unit tests و E2E tests) نجحت بامتياز، فتم دمج التغيير بكل ثقة.

في صباح اليوم التالي، وصلتنا رسالة عاجلة من مدير المنتج على جروب العمل، مرفقة بصورة لواجهة إعدادات المستخدم، وكتب معها جملة لا زلت أتذكرها جيداً: “يا جماعة، شو هاد؟ الصفحة شكلها خربان… ما كانت هيك مبارح!”.

هرعنا جميعاً لنرى الكارثة. الأزرار في تلك الصفحة، التي نادراً ما نزورها، أصبحت متداخلة مع حقول الإدخال، والنصوص تظهر فوق بعضها البعض. الواجهة كانت ببساطة غير قابلة للاستخدام. المشكلة أن اختباراتنا الوظيفية (Functional Tests) لم تكتشف هذا، لأن الزر كان لا يزال “يعمل” عند النقر عليه، هو فقط “شكله” أصبح كارثياً.

بعد ساعات من التوتر والبحث في سجل التغييرات (git blame)، اكتشفنا أن التعديل “البسيط” على الأزرار العامة هو السبب. لقد أثر على مكونات لم نتوقعها أبداً. في تلك اللحظة، أدركت أننا نعتمد على أعيننا وذاكرتنا بشكل خطير جداً لاكتشاف مثل هذه الأخطاء. أدركت أننا بحاجة إلى “عيون آلية” لا تكل ولا تمل، تراقب لنا كل بكسل في واجهاتنا. ومن هنا بدأت رحلتنا مع ما يسمى بـ “الاختبار البصري التراجعي” أو Visual Regression Testing.

ما هو الاختبار البصري التراجعي (Visual Regression Testing)؟

ببساطة شديدة، هو عملية آلية لمقارنة المظهر البصري لواجهتك الحالية مع نسخة مرجعية “سليمة” تم التقاطها في وقت سابق. تخيلها كلعبة “أوجد الفروقات” ولكن لكمبيوترك.

العملية تسير على النحو التالي:

  1. التقاط الصورة المرجعية (Baseline): في المرة الأولى، تقوم الأداة بالتقاط “لقطات شاشة” (Screenshots) لصفحات أو مكونات محددة وتخزينها كمرجع أساسي سليم. هذه هي “الحقيقة” التي سنقارن بها مستقبلاً.
  2. إجراء التغييرات البرمجية: يقوم المطورون بعملهم المعتاد، تعديل الكود، إضافة ميزات جديدة، أو إصلاح أخطاء.
  3. التقاط الصورة الجديدة: بعد التغييرات، وقبل اعتمادها، تقوم نفس الأداة بالتقاط لقطات شاشة جديدة لنفس الصفحات والمكونات.
  4. المقارنة وكشف الفروقات: تقوم الأداة بمقارنة الصور الجديدة بالصور المرجعية بكسل ببكسل.
  5. القرار:
    • إذا لم تكن هناك اختلافات، فالأداة “تبارك” التغيير وتنجح في الاختبار.
    • إذا كانت هناك اختلافات، يفشل الاختبار، وتقوم الأداة بإنشاء تقرير يوضح لك الصور الثلاث: المرجعية (Baseline)، الجديدة (New)، وصورة ثالثة تبرز الاختلافات باللون الأحمر.

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

لماذا لا تكفي الاختبارات التقليدية؟

قد يسأل سائل: “لدينا اختبارات الوحدات (Unit Tests) واختبارات التكامل (Integration Tests) واختبارات النهاية إلى النهاية (E2E Tests)، أليست كافية؟”

الجواب هو لا، ليس عندما يتعلق الأمر بالواجهة البصرية. إليك السبب:

  • اختبارات الوحدات (Unit Tests): تختبر منطق دالة أو مكون معزول. هي لا “ترى” الواجهة ولا تعرف شيئاً عن الألوان أو الأحجام أو المسافات.
  • اختبارات النهاية إلى النهاة (E2E Tests): تحاكي سلوك المستخدم (انقر هنا، اكتب هناك، تحقق من ظهور نص معين). يمكنها التأكد من أن الزر visible، لكنها لا تستطيع بسهولة التأكد من أن لونه هو #FF5733 بالضبط، وأن المسافة بينه وبين العنصر الذي فوقه هي 16px، وأن ظلّه لم يختفِ. محاولة كتابة تأكيدات (assertions) لكل خاصية CSS هي مهمة مستحيلة وغير عملية.

الاختبارات التقليدية تتأكد أن التطبيق “يعمل” بشكل صحيح، بينما الاختبارات البصرية تتأكد أنه “يبدو” بشكل صحيح. وكلاهما ضروري لتجربة مستخدم ممتازة.

كيف نبدأ؟ دليل عملي باستخدام Playwright

هناك العديد من الأدوات الرائعة في هذا المجال مثل Percy.io و Applitools (وهي خدمات مدفوعة وقوية جداً)، أو إضافات لأدوات مثل Cypress و Storybook. ولكني سأركز هنا على أداة أحبها شخصياً وتأتي مع دعم مدمج ممتاز للاختبار البصري: Playwright.

الخطوة 1: إعداد البيئة

إذا لم يكن لديك Playwright، يمكنك إعداده بسهولة:

# أنشئ مشروع جديد أو انتقل إلى مشروعك الحالي
npm init playwright@latest

سيقوم المعالج بإرشادك لإنشاء ملفات الإعداد الأساسية.

الخطوة 2: كتابة أول اختبار بصري

لنفترض أننا نريد اختبار الصفحة الرئيسية لموقعنا. يمكننا كتابة اختبار بسيط في ملف مثل tests/visual.spec.ts:

import { test, expect } from '@playwright/test';

test('يجب أن تبدو الصفحة الرئيسية كما هي دون تغيير', async ({ page }) => {
  // 1. انتقل إلى الصفحة المطلوبة
  await page.goto('http://localhost:3000');

  // 2. التقط صورة وقارنها بالمرجع
  // اسم اللقطة 'homepage.png' هو معرّف فريد لها
  await expect(page).toHaveScreenshot('homepage.png');
});

لاحظ بساطة الكود. كل ما نحتاجه هو سطر واحد: expect(page).toHaveScreenshot().

الخطوة 3: إنشاء الصور المرجعية (Baseline)

عند تشغيل الاختبار لأول مرة، لن تكون هناك صور مرجعية للمقارنة بها. لذلك، نحتاج إلى تشغيل أمر خاص لإنشاء هذه الصور:

npx playwright test --update-snapshots

بعد تشغيل هذا الأمر، ستلاحظ أن Playwright أنشأ مجلداً جديداً بجانب ملف الاختبار يحتوي على صورة homepage.png. هذه هي الصورة المرجعية. قم بإضافتها إلى نظام التحكم بالمصادر (git) مع الكود الخاص بك.

الخطوة 4: كشف التغييرات

الآن، قم بإجراء تغيير بصري بسيط في صفحتك الرئيسية (مثلاً، غيّر لون الخلفية). ثم قم بتشغيل الاختبارات بشكل عادي:

npx playwright test

هذه المرة، سيفشل الاختبار! والرسالة ستكون واضحة: “Screenshot doesn’t match”. الأجمل من ذلك، أن Playwright سيقوم بإنشاء تقرير تفاعلي. افتحه بالأمر:

npx playwright show-report

في التقرير، سترى مقارنة جنباً إلى جنب بين الصورة المتوقعة (Expected)، والصورة الفعلية (Actual)، وصورة توضح الفروقات (Diff). هذا يجعل من السهل جداً تحديد ما إذا كان التغيير مقصوداً أم لا.

نصيحة من أبو عمر: التعامل مع المحتوى الديناميكي

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

يوفر Playwright خيار mask لهذا الغرض بالتحديد:

test('يجب أن تبدو صفحة المقالات كما هي', async ({ page }) => {
  await page.goto('/articles/my-awesome-article');

  // سنقوم بإخفاء عنصر التاريخ قبل التقاط الصورة
  // سيقوم Playwright برسم مربع أسود فوقه أثناء المقارنة
  await expect(page).toHaveScreenshot('article-page.png', {
    mask: [page.locator('.article-timestamp')],
  });
});

بهذه الطريقة، يمكنك اختبار ثبات التصميم العام للصفحة مع تجاهل الأجزاء الديناميكية التي لا تهمك.

نصائح عملية من خبرتي الشخصية

  • ابدأ صغيراً وبالتدريج: لا تحاول تغطية كل صفحات تطبيقك دفعة واحدة. “ابدأ باللي بوجّع”، أي بالصفحات والمكونات الأكثر أهمية وحساسية: الصفحة الرئيسية، مسار الدفع (Checkout flow)، لوحة التحكم الرئيسية.
  • اجعلها جزءاً من الـ CI/CD: القوة الحقيقية تظهر عند دمج هذه الاختبارات في مسار التكامل المستمر والتوزيع المستمر. قم بتشغيلها تلقائياً مع كل طلب سحب (Pull Request). إذا فشل اختبار بصري، يجب أن يمنع ذلك عملية الدمج، مما يجبر المطور على مراجعة التغييرات البصرية.
  • الاختبار على مستوى المكونات: بالإضافة إلى اختبار الصفحات الكاملة، من المفيد جداً اختبار المكونات (Components) بشكل معزول. إذا كنت تستخدم Storybook، فهناك إضافات رائعة تدمجه مع أدوات الاختبار البصري. هذا يجعل الاختبارات أسرع وأكثر استقراراً.
  • ضع هامشاً للخطأ (Threshold): أحياناً، قد تختلف بضعة بكسلات بين بيئة وأخرى بسبب اختلافات بسيطة في عرض الخطوط (font rendering). معظم الأدوات تسمح لك بتعيين “هامش خطأ” (مثلاً 0.1%) لتجاهل هذه الفروقات الطفيفة وتقليل النتائج الإيجابية الخاطئة (false positives).
  • مراجعة اللقطات هي مسؤولية الفريق: عندما يحتوي طلب السحب على تحديثات للقطات الشاشة، يجب على المراجع (Reviewer) ألا يكتفي بالنظر إلى الكود، بل يجب أن يفتح تقرير الفروقات البصرية ويتأكد أن كل تغيير كان مقصوداً ومتوقعاً.

الخلاصة: نم قرير العين يا مطور الواجهات! 😴

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

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

نصيحتي الأخيرة لك: لا تثق بذاكرتك فقط، دع الآلة تساعدك. ابدأ اليوم، ولو بصفحة واحدة أو مكون واحد، وستشكرني لاحقاً. 🙏

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

التوظيف وبناء الهوية التقنية

كانت إجاباتي كارثية: كيف أنقذني أسلوب STAR من جحيم ‘أممم… لا أعرف’ في المقابلات؟

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

22 مايو، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

نمط قاطع الدائرة (Circuit Breaker): الطفاية التي أخمدت حريق الأعطال المتتالية في نظامنا

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

22 مايو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

كانت تطبيقاتنا المالية جزرًا معزولة: كيف أنقذتنا واجهات Open Banking (PSD2) من جحيم تجربة المستخدم؟

بصفتي مطور برمجيات، عانيت طويلًا من عزلة البيانات المالية في البنوك التقليدية. تروي هذه المقالة كيف حررت واجهات البنوك المفتوحة (Open Banking) البيانات، ومكّنت المطورين...

22 مايو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

من شكاوى المستخدمين إلى لوحات المراقبة: كيف أنقذنا Prometheus وGrafana من كابوس ‘الموقع لا يعمل’؟

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

22 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

كانت اجتماعاتنا الفردية مضيعة للوقت: كيف أنقذنا نموذج ‘الموقف-السلوك-التأثير’ (SBI) من جحيم المحادثات السطحية؟

أشارككم تجربتي كقائد فريق تقني، وكيف حوّلنا اجتماعاتنا الفردية (1-on-1s) من لقاءات سطحية ومملة إلى محادثات بنّاءة ومثمرة باستخدام نموذج التغذية الراجعة البسيط والفعّال (الموقف-السلوك-التأثير)....

22 مايو، 2026 قراءة المزيد
​معمارية البرمجيات

ذاكرة الفريق هي التوثيق الوحيد: كيف أنقذتنا ‘سجلات القرارات المعمارية’ (ADRs) من جحيم “لماذا فعلنا ذلك؟”

أشارككم قصة حقيقية عن ضياع المعرفة في فريقنا وكيف تحولت 'سجلات القرارات المعمارية' (ADRs) إلى منقذنا. اكتشفوا كيف يمكن لهذه الأداة البسيطة أن تنهي جحيم...

22 مايو، 2026 قراءة المزيد
البودكاست