الاختبار البصري لتطبيقات الصفحة الواحدة: حالات أكثر، مخاطر أكثر، أسباب أكثر للاختبار
النقاط الرئيسية
- تُنتج SPA آلياً حالات بصرية أكثر من موقع متعدد الصفحات تقليدي، وكل حالة يمكن أن تحتوي على انحدار
- التنقل دون إعادة تحميل، والانتقالات المتحركة، والعرض الشرطي تخلق مجموعات بصرية لا تغطيها الاختبارات الوظيفية
- الاختبار البصري الآلي هو النهج الواقعي الوحيد لالتقاط والتحقق من جميع حالات SPA
- تجاهل الاختبار البصري في SPA يعني القبول بأن معظم حالات واجهتك لن يتم التحقق منها أبداً
تطبيق الصفحة الواحدة (Single Page Application)، وفقاً لتعريف MDN Web Docs (Mozilla Developer Network)، هو «تطبيق ويب يتفاعل مع المستخدم عن طريق إعادة كتابة الصفحة الحالية ديناميكياً بدلاً من تحميل صفحات جديدة كاملة من الخادم، مما يوفر تجربة مستخدم أكثر سلاسة مشابهة للتطبيقات الأصلية» (MDN, SPA — Single-page application).
هذا التعريف التقني أنيق. واقع ضمان الجودة المترتب عليه أقل أناقة بكثير.
لأنه بإعادة كتابة الصفحة ديناميكياً بدلاً من تحميل صفحات جديدة، تُركّز SPA في مستند HTML واحد عدداً من الحالات البصرية يتجاوز بكثير ما يمكن لموقع تقليدي إنتاجه. وكل حالة هي مكان يمكن فيه لشيء أن يُعرض بشكل خاطئ.
المواقع متعددة الصفحات كانت تملك ميزة لم يعترف بها أحد
قبل عصر SPA، كان كل URL يُقابل صفحة مستقلة، تُحمَّل بالكامل من الخادم. كان ذلك بطيئاً، ومتقطعاً أحياناً، لكنه امتلك ميزة كبيرة من منظور QA: كل صفحة كانت حالة منفصلة ومستقرة. يمكنك التقاطها والتحقق منها والانتقال إلى التالية.
موقع من عشرين صفحة كان له عشرون حالة رئيسية. حرفياً، يمكنك سردها على لوح أبيض والتحقق منها واحدة تلو الأخرى أثناء الاختبار. كان ذلك قابلاً للإدارة.
SPA حطمت تلك البساطة. تطبيق React أو Vue أو Angular متوسط التعقيد لا يُختزل في مساراته. كل مسار يمكن أن يعرض عشرات الحالات المختلفة بناءً على البيانات المُحمَّلة، وتفاعلات المستخدم، والأذونات، وظروف الخطأ، وحالات التحميل.
خذ صفحة لوحة تحكم في SPA. يمكنها عرض حالة تحميل أولية مع skeletons. ثم الحالة مع البيانات. ثم حالة البيانات الفارغة (أول استخدام). ثم حالة خطأ الشبكة. ثم الحالة مع فلتر نشط. ثم الحالة مع نافذة منبثقة مفتوحة. ثم الحالة مع tooltip مرئي. كل حالة لها مظهر بصري مميز سيراه مستخدموك.
اضرب ذلك في عدد مسارات تطبيقك، وستفهم لماذا اختبار SPA يدوياً هو وهم.
التحديات البصرية الخاصة بتطبيقات SPA
تطبيقات SPA ليست مجرد مواقع بحالات أكثر. إنها تُدخل فئات كاملة من المشاكل البصرية التي لا وجود لها في المواقع التقليدية متعددة الصفحات.
التنقل دون إعادة تحميل
في موقع تقليدي، يُطلق التنقل إعادة تحميل كاملة للصفحة. المتصفح يُدمّر DOM الحالي، يُحمّل HTML الجديد، يُطبّق CSS، يُنفّذ JavaScript. كل صفحة تبدأ من حالة نظيفة.
في SPA، يُعدّل التنقل DOM الحالي دون إعادة تحميل. المكونات تُركَّب وتُفكَّك. الحالة العامة تستمر بين العروض. الآثار الجانبية تتراكم.
هذا يخلق مشكلة خفية لكنها حقيقية: مظهر العرض يمكن أن يعتمد على مسار التنقل المتبع للوصول إليه. مكون يُركَّب بشكل صحيح عند الوصول المباشر للمسار قد يُعرض بشكل مختلف عند الوصول بعد التنقل من عرض آخر، لأن حالة عامة متبقية تؤثر على العرض.
الاختبارات الوظيفية التي تصل لكل مسار مباشرة عبر URL تفوت تماماً هذه الانحدارات المرتبطة بالتنقل التسلسلي. فقط اختبار يُعيد إنتاج مسار المستخدم الحقيقي ويلتقط النتيجة بصرياً يمكنه اكتشافها.
الانتقالات والحركات
تستخدم SPA الانتقالات بكثافة لتنعيم التنقل. المكون لا يختفي فوراً: يتحرك للخارج بينما التالي يتحرك للداخل. هذه الانتقالات عنصر حاسم في تجربة المستخدم.
وهي مصدر غزير لأخطاء البصرية. انتقال مُقاطع يمكن أن يترك مكونين متراكبين. توقيت سيئ يمكن أن يخلق وميضاً في المحتوى. حركة CSS لا تكتمل بشكل صحيح يمكن أن تترك عنصراً في حالة بصرية وسيطة إلى أجل غير مسمى.
اختبار هذه الانتقالات يدوياً يتطلب انتباهاً مستمراً وتوقيتاً دقيقاً. على المختبر ملاحظة اللحظة الدقيقة للانتقال، بالسرعة الصحيحة، في المتصفح الصحيح. إنه هش بشرياً وغير قابل للتكرار.
الاختبار البصري الآلي يمكنه التقاط حالات وسيطة للانتقال بأخذ لقطات في لحظات دقيقة من دورة الحركة، كاشفاً التراكبات والومضات والحالات غير المتسقة التي تراها العين البشرية لكن لا تستطيع توثيقها بشكل منهجي.
العرض الشرطي
تطبيقات SPA تعشق العرض الشرطي. اعرض هذا المكون إذا كان المستخدم مسجلاً. أظهر هذا الشعار إذا كانت الميزة في نسخة تجريبية. غيّر هذا الزر إذا كانت السلة تحتوي عناصر. أخفِ هذا القسم إذا انتهى الاشتراك.
كل شرط يخلق تفرعاً في شجرة الحالات البصرية الممكنة. مع خمسة شروط مستقلة، لديك نظرياً اثنتان وثلاثون مجموعة بصرية مختلفة. مع عشرة شروط، أكثر من ألف.
لا أحد يختبر ألف مجموعة يدوياً. لا أحد يسردها بشكل شامل في حالات اختبار وظيفية. ومع ذلك فهي موجودة، ومستخدموك يصادفونها.
الاختبار البصري لا يدعي تغطية هذه المجموعات بشكل شامل. لكنه يغطي أكثر بما لا يُقاس من الاختبارات اليدوية أو الوظيفية، لأن كل لقطة بصرية تتحقق من الشاشة بأكملها، بما في ذلك العناصر التي لم يفكر أحد في اختبارها صراحة.
حالات التحميل غير المتزامن
في موقع متعدد الصفحات، التحميل حدث ثنائي: الصفحة مُحمَّلة أو لا. في SPA، التحميل عملية مستمرة وجزئية. مكون قد يكون مُحمَّلاً بينما آخر لا يزال ينتظر بياناته. الصفحة في حالة «جاهزة» و«قيد التحميل» في نفس الوقت.
حالات التحميل الجزئية هذه ذات أهمية بصرية. skeletons وspinners وplaceholders الخاصة بك هي عناصر واجهة كاملة. skeleton بحجم خاطئ لا يتوافق مع حجم المحتوى النهائي يخلق قفزة بصرية مزعجة. spinner في موضع خاطئ قد يتراكب على مكون آخر. placeholder لا يختفي أبداً هو خطأ مرئي.
الاختبار البصري يلتقط هذه الحالات الوسيطة ويقارنها بمرجعها، كاشفاً التناقضات التي لا تراها الاختبارات الوظيفية (التي عادة تنتظر اكتمال التحميل قبل التحقق) أبداً.
إدارة الحالة هي مُضاعف للحالات البصرية
تعتمد بنية SPA الحديثة على إدارة حالة مركزية (Redux، Vuex، Pinia، NgRx، Zustand). حالة التطبيق مُخزَّنة في store عام يُحدد ما يظهر على الشاشة.
هذا النمط المعماري ممتاز لصيانة الكود. لكنه مروع لقابلية الاختبار البصري، لأنه يُضاعف بشكل أسّي المجموعات الممكنة من الحالات.
store الخاص بك يحتوي حالة المصادقة. حالة السلة. تفضيلات المستخدم. البيانات المُخزّنة مؤقتاً. الإشعارات المعلقة. Feature flags. كل مجموعة من هذه الحالات تُنتج محتملاً عرضاً بصرياً مختلفاً.
مستخدم مسجل بسلة فارغة وإشعارات غير مقروءة والوضع الداكن مُفعَّل لا يرى نفس ما يراه زائر مجهول بالوضع الفاتح. وكلاهما يحتاج اختباراً بصرياً. هذه المجموعات ليست حالات نظرية حدّية. إنها سيناريوهات حقيقية يعيشها مستخدموك يومياً.
الاختبار البصري الآلي يسمح بالتقاط هذه المجموعات عبر تهيئة حالة store قبل كل لقطة. لم تعد تختبر مجرد صفحات: تختبر حالات تطبيقية كاملة، كل منها بعرضها البصري المُتحقق منه.
Client-side routing وفخاخه البصرية
يُدير router تطبيق SPA التنقل من جانب العميل. هذا ما يُمكّن التبديل الفوري للعرض دون إعادة تحميل. لكنه يخلق أيضاً فخاخاً بصرية محددة.
الفخ الأول هو موضع التمرير. في موقع متعدد الصفحات، كل تنقل يُعيد التمرير للأعلى. في SPA، يُحفظ موضع التمرير بين العروض ما لم يُهيَّأ router لإعادة ضبطه. النتيجة: مستخدم ينتقل من صفحة طويلة إلى قصيرة قد يجد شاشة فارغة، مُمرَّرة إلى ما بعد المحتوى. هذا خطأ بصري لا تكشفه الاختبارات الوظيفية لكن الاختبار البصري يلتقطه فوراً.
الفخ الثاني هو deep linking. يمكن للمستخدم الوصول مباشرة لأي مسار في SPA عبر رابط مُشارك أو مفضلة. يجب أن يكون العرض صحيحاً حتى بدون سياق التنقل الطبيعي. لكن SPA قد تحتاج بيانات مُحمَّلة في مسارات سابقة. بدون تلك البيانات، قد تُعرض المكونات فارغة أو بقيم افتراضية غير متوقعة.
الفخ الثالث هو التنقل للخلف. زر «رجوع» في المتصفح في SPA لا يُعيد تحميل الصفحة السابقة: يستعيد حالة من السجل. إذا كانت استعادة الحالة غير مكتملة، قد يكون العرض المعروض مختلفاً بصرياً عما كان عليه أصلاً. اختبار بصري يقارن العرض المُستعاد بالأصلي يكشف هذه التناقضات.
النهج المُهيكل للاختبار البصري لتطبيقات SPA
اختبار SPA بصرياً يتطلب نهجاً مُهيكلاً يأخذ في الاعتبار تعقيدها الخاص.
البُعد الأول هو التغطية حسب المسار. كل مسار في تطبيقك يجب أن يمتلك على الأقل لقطة بصرية مرجعية في حالته الافتراضية. هذا المستوى الأساسي، مُعادل لاختبار كل صفحة في موقع متعدد الصفحات.
البُعد الثاني هو التغطية حسب الحالة. لكل مسار، حدد الحالات المتمايزة بصرياً: حالة فارغة، حالة مُحمَّلة، حالة خطأ، حالة تحميل. كل حالة تستحق لقطة مرجعية خاصة.
البُعد الثالث هو التغطية حسب التفاعل. النوافذ المنبثقة، القوائم المنسدلة، tooltips، الألواح الجانبية التي تُفتح بالتفاعل هي حالات بصرية بحد ذاتها. يجب تشغيلها والتقاطها.
البُعد الرابع هو التغطية حسب المسار. بعض الأخطاء البصرية تظهر فقط في سياق تنقل محدد. الاختبارات التي تُعيد إنتاج مسارات مستخدم حقيقية (تسجيل دخول، تنقل للوحة التحكم، فتح عنصر، عودة للقائمة) تلتقط هذه الانحدارات السياقية.
هذا النهج رباعي الأبعاد يبدو مُخيفاً. وهو كذلك، إذا اختبرت يدوياً. مع أداة اختبار بصري آلي، كل بُعد يُترجم إلى تهيئة اختبار، لا إلى ساعات من العمل البشري.
تطبيقات SPA تستحق اختباراً بصرياً أكثر، لا أقل
هناك إغراء مفهوم: أمام تعقيد SPA، بعض الفرق تُقلل جهدها في الاختبار البصري. «حالات كثيرة جداً، لا نستطيع تغطية كل شيء، لنركز على الاختبارات الوظيفية.»
هذا رد الفعل هو عكس المطلوب تماماً. كلما زادت الحالات البصرية في تطبيقك، زادت الحاجة للاختبار البصري. بالتحديد لأن SPA معقدة بصرياً، الاختبار اليدوي لا يكفي والأتمتة البصرية تصبح لا غنى عنها.
الاختبارات الوظيفية تتحقق من أن تطبيقك يفعل ما يجب. الاختبار البصري يتحقق من أنه يبدو كما يجب. في SPA حيث المظهر يتغير باستمرار بناءً على الحالة، هذا التحقق البصري ليس رفاهية. إنه ضرورة.
كل حالة غير مُختبرة بصرياً هي حالة يمكن أن تنحدر بصمت. وفي SPA، عدد الحالات غير المُختبرة يتجاوز سريعاً عدد المُختبرة، ما لم تستخدم أداة قادرة على التقاطها آلياً.
الأسئلة الشائعة
هل يعمل الاختبار البصري مع جميع أطر عمل SPA (React، Vue، Angular، Svelte)؟
الاختبار البصري لا يعتمد على إطار العمل. يلتقط المظهر النهائي المعروض في المتصفح، بغض النظر عن إطار العمل المُستخدم لإنتاجه. سواء كانت SPA مبنية بـ React أو Vue أو Angular أو Svelte أو أي إطار آخر، النتيجة واحدة: HTML وCSS وJavaScript معروضة في متصفح. الاختبار البصري يعمل على هذا المستوى، مستوى العرض النهائي، مما يجعله متوافقاً عالمياً.
كيف تُدار الحركات والانتقالات في اختبارات SPA البصرية؟
الحركات تُمثل تحدياً خاصاً. أفضل نهج هو تعطيل حركات CSS وJavaScript أثناء اللقطات البصرية للحصول على مقارنات مستقرة وقابلة للتكرار. بعض أدوات الاختبار البصري تقدم هذا الخيار أصلاً. بدلاً من ذلك، يمكنك التقاط الحالات قبل وبعد الانتقال بدلاً من أثنائه، مما يُزيل التباين المرتبط بتوقيت الحركة مع التحقق من الحالات البصرية للبداية والنهاية.
كيف يُختبر بصرياً الحالات التي تعتمد على بيانات ديناميكية (API، قاعدة بيانات)؟
الحل القياسي هو mocking للـ API. تُهيئ اختباراتك لاعتراض المكالمات الشبكية وإرجاع بيانات حتمية. هذا يسمح بإعادة إنتاج كل حالة بصرية بشكل موثوق: بيانات مُحمَّلة، بيانات فارغة، خطأ شبكة، تحميل بطيء. بدون mocking، ستتغير لقطاتك البصرية مع كل تنفيذ بناءً على البيانات الحقيقية، مما يجعل المقارنة مستحيلة.
كم حالة بصرية يجب اختبارها لتطبيق SPA متوسط الحجم؟
لا يوجد رقم سحري، لكن قاعدة عملية مفيدة هي تغطية ثلاث حالات على الأقل لكل مسار: الحالة الاسمية (بيانات مُحمَّلة)، الحالة الفارغة (بدون بيانات)، وحالة الخطأ. لتطبيق SPA بعشرين مساراً، هذا يمثل حداً أدنى من ستين لقطة مرجعية. أضف حالات التفاعل (نوافذ منبثقة، قوائم منسدلة، ألواح) وتصل بسهولة إلى مئة إلى مئة وخمسين لقطة. يبدو كثيراً، لكنه قابل للإدارة تماماً مع أداة آلية.
هل يحل الاختبار البصري محل اختبارات الوحدة واختبارات end-to-end في SPA؟
لا، وليس هذا هدفه. اختبارات الوحدة تتحقق من منطق العمل لمكوناتك. اختبارات end-to-end تتحقق من المسارات الوظيفية الكاملة. الاختبار البصري يتحقق من المظهر. هذه المستويات الثلاثة متكاملة. الاختبار البصري يملأ الفجوة التي يتركها الآخران: يكتشف الانحدارات البصرية التي لا تُلاحظ في التحققات الوظيفية. زر قد يكون وظيفياً لكن غير مرئي. نموذج قد يُرسل بشكل صحيح لكن بتخطيط مكسور. فقط الاختبار البصري يلتقط هذه المشاكل.
ألا تكون اختبارات SPA البصرية بطيئة جداً في التنفيذ؟
SPA الحديثة تُعرض في بضع مئات من الميلي ثانية. اللقطة البصرية نفسها تستغرق بضع عشرات ميلي ثانية إضافية. مقارنة الصور فورية تقريباً. لمجموعة من مئة لقطة، الوقت الإجمالي عادة من دقيقتين إلى خمس دقائق، بما في ذلك وقت التنقل بين الحالات. هذا ضئيل مقارنة بمدة pipeline CI/CD كامل وأسرع بما لا يُقاس من اختبار يدوي لن يغطي إلا جزءاً صغيراً من تلك الحالات.
هل لدى SPA الخاص بك عشرات الحالات البصرية التي لا يختبرها أحد؟ حان وقت التغيير.