شرح مفصل لنموذج كائن الصفحة (POM) في Playwright مع أمثلة تطبيقية لأتمتة اختبارات واجهات الويب باستخدام جافاسكريبت.
Key Takeaways
- نموذج كائن الصفحة يفصل بين عناصر الصفحة واختبارات الأتمتة مما يقلل التكرار.
- يسهل صيانة الاختبارات عند تغيير عناصر واجهة المستخدم.
- يمكن إعادة استخدام فئات كائن الصفحة في اختبارات متعددة.
- تنظيم الكود في ملفات منفصلة لكل صفحة يعزز وضوح وسهولة إدارة المشروع.
- Playwright يدعم تطبيق نموذج كائن الصفحة بكفاءة باستخدام جافاسكريبت.
What the video covers
- تعريف نموذج كائن الصفحة (Page Object Model) وأهميته في فصل عناصر الصفحة عن اختبارات الأتمتة.
- شرح المشاكل التي تواجه أتمتة الاختبارات بدون استخدام نموذج كائن الصفحة مثل تكرار الكود وصعوبة الصيانة.
- توضيح كيفية إنشاء فئات منفصلة لكل صفحة تحتوي على عناصر الصفحة والإجراءات الخاصة بها.
- عرض مثال عملي على تطبيق التجارة الإلكترونية يتضمن صفحات تسجيل الدخول، الصفحة الرئيسية، وصفحة العربة.
- شرح كيفية استخدام نموذج كائن الصفحة لتقليل تكرار الكود وزيادة قابلية إعادة الاستخدام.
- تنفيذ نموذج كائن الصفحة باستخدام Playwright وجافاسكريبت مع تنظيم الملفات في مجلد pages.
- توضيح كيفية كتابة اختبارات باستخدام فئات كائن الصفحة بدلاً من كتابة العناصر مباشرة في كل اختبار.
- عرض كيفية التعامل مع التغييرات في عناصر الصفحة بسهولة عن طريق تعديل فئة كائن الصفحة فقط.
- شرح خطوات تنفيذ الاختبار وتشغيله باستخدام نموذج كائن الصفحة.
- تأكيد على فوائد نموذج كائن الصفحة في تحسين صيانة الاختبارات وتسهيل إدارتها.
Chapters
- 00:00مقدمة ونظرة عامة على نموذج كائن الصفحة
- 02:53مشاكل الأتمتة بدون نموذج كائن الصفحة
- 05:36عرض تطبيق التجارة الإلكترونية وأهم الصفحات
- 07:42شرح كيفية إنشاء فئات كائن الصفحة
- 11:32كتابة الاختبارات بدون نموذج كائن الصفحة
- 12:39تحويل الاختبارات لاستخدام نموذج كائن الصفحة
- 14:12تنظيم ملفات الصفحات وإنشاء الفئات
- 15:36تشغيل الاختبارات ومزايا نموذج كائن الصفحة
- 19:08التعامل مع عناصر الصفحة المتعددة وتحديثها بسهولة
- 23:51خاتمة وفوائد نموذج كائن الصفحة
Full Transcript — Download SRT & Markdown
Speaker A
مرحباً بالجميع، أهلاً بكم. في فيديو اليوم، دعونا نحاول فهم نموذج كائن الصفحة (Page Object Model) في بلايرايت (Playwright). إذاً، ما هو نموذج كائن الصفحة بشكل أساسي؟ نموذج كائن الصفحة هو إطار عمل أو نمط نقوم فيه بالحفاظ على عناصر
Speaker A
الصفحة في ملفات منفصلة. عادةً، عندما تكتب اختباراتك، فإنها تتضمن جميع عناصر الصفحة والإجراءات المقابلة لها. لذا، في نمط نموذج كائن الصفحة، سنحاول الفصل بينها. في ملف واحد سنحتفظ بجميع عناصر الصفحة، وفي ملف آخر سنكتب الاختبار الفعلي. في صفحة الويب
Speaker A
أو في تطبيقنا، إذا كان لدي صفحات متعددة، فسننشئ لكل صفحة ملفاً منفصلاً يحتوي فقط على عناصر تلك الصفحة.
Speaker A
دعوني أحاول شرح سبب حاجتنا بالضبط لنموذج كائن الصفحة هذا. ما هي المزايا، وإذا لم نستخدم نموذج كائن الصفحة، فما هي العيوب التي يجب أن نفهمها أولاً؟ دعوني أشرح هذا بمثال. هنا لدي ثلاث صفحات مختلفة في تطبيقي. لنفترض أن لدي
Speaker A
صفحة تسجيل دخول ثم صفحة رئيسية. بمجرد تسجيل الدخول بنجاح، ستصل إلى الصفحة الرئيسية، ومنها يمكننا اختيار المنتج، ثم إضافته إلى عربة التسوق، ثم إجراء الدفع، وهكذا. هذا هو سير عمل تطبيق التجارة الإلكترونية العادي.
Speaker A
أليس كذلك؟ لنفترض أن لدي حالتي اختبار مختلفتين. حالة الاختبار الأولى هي: أولاً أحتاج إلى تسجيل الدخول للتطبيق، ثم اختيار منتج وإضافته للعربة، ثم الذهاب لنافذة العربة والتحقق مما إذا كان المنتج قد أضيف أم لا.
Speaker A
هذه هي حالة الاختبار الأولى. دعونا نرى حالة اختبار أخرى. أريد تسجيل الدخول إلى التطبيق. بعد ذلك، يجب أن أذهب مباشرة إلى عربة التسوق، وأحذف أي منتج مضاف مسبقاً، وأخيراً أتحقق مما إذا كان قد تم حذف المنتج بنجاح أم لا. إذاً،
Speaker A
هاتان حالتا اختبار مختلفتان لدي. الآن، إذا نظرت إلى هنا، عند أتمتة حالة الاختبار الأولى، كم صفحة ستحتاج للرجوع إليها هنا؟ أولاً، نحتاج للرجوع لعناصر صفحة تسجيل الدخول، ثم عناصر الصفحة الرئيسية، ثم بعض العناصر الموجودة في صفحة العربة. لذا،
Speaker A
علينا التفاعل مع عناصر مختلفة من صفحات ويب مختلفة. وإذا نظرت إلى حالة الاختبار الأخرى أيضاً، فسنحتاج للتفاعل مع عناصر من صفحات مختلفة. عادة ما يحدث أنه إذا لم أستخدم فئة كائن الصفحة أو نموذج كائن الصفحة، فسنضطر في كل
Speaker A
حالة اختبار إلى تحديد تلك العناصر وتنفيذ الإجراءات عليها. وهذا سيؤدي بشكل أساسي إلى تكرار العمل. على سبيل المثال، لنفترض أن لدي ثلاثة أنواع مختلفة من العناصر في صفحة تسجيل الدخول. لنفترض أن لدي عنصر اسم المستخدم وعنصر كلمة المرور، ثم
Speaker A
يتعين علي النقر على زر تسجيل الدخول. هناك ثلاثة عناصر مختلفة موجودة في صفحة تسجيل الدخول. الآن عند أتمتة حالة الاختبار الأولى، أحتاج إلى تحديد هذه العناصر الثلاثة ثم تنفيذ الإجراء. وبالمثل، إذا أردت أتمتة حالة اختبار أخرى، علينا مجدداً العثور على تلك
Speaker A
العناصر وتنفيذ الإجراءات عليها. لذا، يمكننا الإشارة إلى نفس الصفحة وتحديد نفس العناصر وتنفيذ الإجراءات في حالات اختبار متعددة. وفي هذه الحالة، سيحدث تكرار للعناصر في حالات الاختبار المتعددة. يتعين علينا تحديد موقع هذه العناصر لعدة مرات.
Speaker A
تلك هي المشكلة الأولى. المشكلة الثانية هي: لنفترض أنني استخدمت هذه العناصر في عدة حالات اختبار، وإذا حدث أي تغيير في أداة تحديد الموقع أو في سمات تلك العناصر، فسنحتاج للذهاب وتعديلها في كل حالة اختبار، أليس كذلك؟ تلك هي مشكلة أخرى.
Speaker A
لنفترض أن عناصر صفحة تسجيل الدخول هذه مُشار إليها في 10 حالات اختبار مختلفة؛ في كل حالة اختبار سنحتاج لتعديل هذه العناصر، وهذه مشكلة أخرى. لذا يمكننا الآن التغلب على هاتين التحديين باستخدام نهج نموذج كائن الصفحة أو نمط نموذج كائن
Speaker A
الصفحة. في نمط نموذج كائن الصفحة، ما سنفعله هو أنه لكل صفحة - لنفترض وجود 10 صفحات في تطبيقنا - سننشئ ملفاً منفصلاً ونسميها فئات كائن الصفحة. فئات كائن الصفحة، وهذا النوع من الفئات يحتوي على العناصر والإجراءات المقابلة لها. على سبيل المثال، هناك
Speaker A
صفحة تسجيل دخول. بالنسبة لصفحة تسجيل الدخول هذه، سأنشئ فئة كائن صفحة واحدة تحتوي فقط على عناصر صفحة تسجيل الدخول مع الإجراءات. وبالنسبة للصفحة الرئيسية، سأنشئ فئة كائن صفحة أخرى تحتوي فقط على العناصر التي تنتمي للصفحة الرئيسية.
Speaker A
وسأنشئ فئة كائن صفحة أخرى لصفحة سلة التسوق تحتوي على عناصر من صفحة سلة التسوق.
Speaker A
وهكذا، لديك عدد (ن) من صفحات الويب. لكل صفحة ستنشئ فئة مختلفة تحتوي فقط على العناصر والإجراءات المقابلة لها. الآن سنقوم بالاستفادة من هذه الصفحات أو الإشارة إليها في حالات اختبار متعددة. يُطلق على هذا في الأساس نموذج كائن الصفحة أو نمط نموذج
Speaker A
كائن الصفحة. حسنًا. إذن، دعونا نحاول تنفيذ هذا في بلاي رايت. فكيف يمكننا تنفيذ فئة كائن الصفحة أو نموذج كائن الصفحة لأتمتة حالات الاختبار؟ حسنًا. الآن دعوني أعرض لكم التطبيق الذي سأقوم بأتمتته. هنا، أه لدي تطبيق. دعوني أفتحه في
Speaker A
متصفحي. وهذه هي صفحتي الرئيسية. وهذه هي صفحة تسجيل الدخول الخاصة بي. أولاً نحتاج إلى النقر على تسجيل الدخول ثم سأنتقل إلى صفحة تسجيل الدخول. إذن هذه هي نافذة تسجيل الدخول.
Speaker A
أولاً يجب أن نبدأ بتسجيل الدخول بمجرد تشغيل التطبيق. هنا هذا هو عنصر اسم المستخدم. سأقوم فقط بتمرير عنصر ما هنا. اه، اسم المستخدم الخاص بي. وهذا هو اسم المستخدم الخاص بي ثم سأقوم بإدخال كلمة المرور والنقر على
Speaker A
تسجيل الدخول. تنتمي هذه العناصر الثلاثة إلى صفحة تسجيل الدخول وبمجرد تسجيل الدخول بنجاح، هذه هي الصفحة الرئيسية. في هذه الصفحة الرئيسية يمكنك العثور على منتجات متعددة هنا.
Speaker A
هناك روابط متعددة، ومنتجات متعددة، ويمكنك رؤية بعض خيارات القائمة هنا. الرئيسية، اتصل بنا، من نحن، وما إلى ذلك.
Speaker A
إذن هذه العناصر ستكون جزءًا من الصفحة الرئيسية. سنقوم بإنشاء فئة كائن صفحة أخرى تحتوي على العناصر التي تنتمي إلى الصفحة الرئيسية.
Speaker A
بعد ذلك، سأختار أحد المنتجات من هذه الصفحة الرئيسية ثم سأضيفه إلى عربة التسوق. سأنقر على إضافة إلى العربة ثم أغلق هذا. الآن بمجرد إضافة المنتج، يجب أن أذهب إلى صفحة العربة.
Speaker A
الصفحة الثالثة. يمكنك فقط النقر على العربة هنا. ثم ستنتقل إلى الصفحة الثالثة. هذه هي صفحة العربة. هنا سأتحقق مما إذا كان المنتج قد تمت إضافته بنجاح أم لا. إذن هناك إجمالي ثلاث صفحات مختلفة يجب أن أتفاعل معها. الأولى هي صفحة
Speaker A
تسجيل الدخول. الثانية هي الصفحة الرئيسية، وفي الصفحة الرئيسية يمكننا اختيار المنتج وإضافته إلى العربة، وفي صفحة العربة يمكنني التأكد مما إذا كان المنتج قد أضيف أم لا، كما يمكننا حذف المنتج أو تعديله. هذه هي العمليات التي يمكنني القيام بها في
Speaker A
صفحة العربة. حسنًا، هذه هي الصفحات الثلاث المختلفة التي يجب أن أتفاعل معها. الآن سأقوم بإنشاء حالة اختبار وسأشير فيها إلى صفحات متعددة.
Speaker A
حسنًا، حالة اختبار واحدة ستشير إلى صفحات متعددة. سأحتفظ بجميع كائنات الصفحة أو عناصر الصفحة في فئات مختلفة. الآن دعونا نرى كيف يمكننا تحقيق ذلك باستخدام نموذج كائن الصفحة أو نمط نموذج كائن الصفحة.
Speaker A
للقيام بذلك، قمت بالفعل بأخذ فئة واحدة وهي pom test.spec.js التي تم إنشاؤها بالفعل داخل مجلد الاختبار. وإذا نظرت إلى هذا الكود بالتحديد هنا، فهذا هو الكود بدون استخدام نموذج كائن الصفحة (POM).
Speaker A
لذا فأنا أقوم بتشغيل تطبيقي مباشرة، ثم أنقر على رابط تسجيل الدخول، ثم أدخل اسم المستخدم هنا، ثم كلمة المرور، ثم أنقر على تسجيل الدخول، وأتم عملية الدخول بنجاح.
Speaker A
هذا كود بسيط قمت بكتابته، وهو بدون استخدام نموذج كائن الصفحة. في هذا الكود، نحاول تحديد العنصر وتنفيذ الإجراء المقابل له هنا. ولكن في الواقع، ما سنفعله هو أننا سنقوم بفصل هذا. لذا سنقوم بفصل عناصر الصفحة والإجراءات في فئة
Speaker A
أخرى، ويمكننا الرجوع إلى تلك الفئة المحددة في حالات اختبار متعددة. هذا هو الهدف الرئيسي من استخدام نموذج كائن الصفحة.
Speaker A
حسناً. هذا هو الكود باستخدام نموذج كائن الصفحة، حيث يمكننا عادةً كتابة البرنامج النصي بهذا الشكل.
Speaker A
بدون نموذج كائن الصفحة، كيف يمكننا تحقيق ذلك؟ قبل ذلك، دعوني أشغل الاختبار وأرى كيف سيعمل.
Speaker A
سأحاول تنفيذ هذا من نافذة وحدة التحكم (الكونسول). دعوني أغلق هذه النافذة وأفتح محطة (تيرمينال) جديدة.
Speaker A
حسناً، الآن أحاول تشغيل الاختبار. اسم الاختبار الخاص بي هو home test.spec.js. حسناً. الآن أقوم بتشغيل الاختبار، وتفتح صفحتي، ويتم تسجيل الدخول بنجاح.
Speaker A
هذا الاختبار بدون استخدام نموذج كائن الصفحة. حسناً. الآن سأقوم بتحويله إلى نموذج كائن الصفحة.
Speaker A
كيف يمكننا الحفاظ على العناصر في ملفات مختلفة؟ ما سأفعله هو أنني سأحاول إزالة هذا. أول شيء هو أننا بحاجة إلى التفاعل مع صفحة تسجيل الدخول.
Speaker A
هذا هو الشيء الأول، ثم نحتاج إلى الذهاب إلى الصفحة الرئيسية، ثم نحتاج إلى الذهاب إلى صفحة سلة التسوق.
Speaker A
لذا يجب أن نتفاعل مع ثلاث صفحات مختلفة. سأضع عناصر صفحة تسجيل الدخول في ملف واحد، وعناصر الصفحة الرئيسية في ملف آخر.
Speaker A
سأضع عناصر صفحة سلة التسوق في ملف آخر. بادئ ذي بدء، نحتاج إلى إنشاء ثلاث فئات مختلفة لكائنات الصفحة. حسناً.
Speaker A
ويمكننا استخدام فئات كائنات الصفحة تلك في حالات اختبار متعددة، أو يمكن لحالات اختبار متعددة الرجوع إلى نفس عناصر فئة كائن الصفحة. الآن لنحاول إنشاء فئات كائنات صفحة لهذه الصفحات الثلاث. لقد أنشأت بالفعل مجلداً جديداً يسمى pages في
Speaker A
مجلد المشروع الخاص بي. الآن بداخل هذا المجلد، أنشأت ثلاثة ملفات JavaScript مختلفة وهي cartpage.js، وhomepage.js، وloginpage.js. لذا، دعونا أولاً نلقي نظرة على loginpage.js وكيف أنشأت فئة كائن الصف.
Speaker A
عندما تنشئ فئة كائن صفحة جديدة، فإن أول شيء هو أننا بحاجة إلى إنشاء فئة مثل هذه الفئة في JavaScript. هذه هي الطريقة التي نحتاجها لإنشاء فئة (class). اسم الفئة، وداخل الفئة نحتاج أولاً لإنشاء مُنشئ (constructor). فما المقصود بالمُنشئ؟
Speaker A
يعني أنه كلما أنشأت كائناً لهذه الفئة، سيتم استدعاء المُنشئ تلقائياً. لذا داخل المُنشئ، يجب أن نأخذ أداة الصفحة (page fixture) كمعامل، وهذا سنحصل عليه من حالة الاختبار ، وسنشير إلى نفس أداة الصفحة هذه لتحديد العناصر في المُنشئ.
Speaker A
ما نحتاج إلى القيام به أولاً هو كتابة جميع المحددات (locators). على سبيل المثال، في صفحة تسجيل الدخول، أحتاج إلى ثلاثة أشياء في تطبيقنا. دعني أسجل الخروج. وهذه هي الصفحة الرئيسية، صفحة البداية. في هذه الصفحة، أحتاج إلى أنواع مختلفة من
Speaker A
العناصر، مثل رابط تسجيل الدخول. هذا هو الشيء الأول. بمجرد النقر عليه، ستحصل على اسم المستخدم وكلمة المرور وزر تسجيل الدخول. إذن هذه هي العناصر الثلاثة.
Speaker A
بالمجمل، يجب علي تحديد أربعة عناصر. لذلك، بالنسبة لهذه العناصر الأربعة، قمت بالتقاط المحدد. هذا هو المُعرف (ID) لرابط تسجيل الدخول، وهذا هو المُعرف لصندوق إدخال اسم المستخدم. هذا هو المُعرف لصندوق إدخال كلمة المرور. وهذا هو مسار (X path) الخاص بزر
Speaker A
تسجيل الدخول. إذن هذا هو مسار (X path) الخاص بزر تسجيل الدخول. هذه هي العناصر الثلاثة، وسأقوم بتخزين سمات هذه العناصر الثلاثة في متغيرات مختلفة.
Speaker A
يمكنك رؤية ` this.page`. فأي صفحة نحصل عليها من الاختبار نقوم بتعيينها في متغير الفئة. لذا فإن ` this` تمثل دائماً الفئة.
Speaker A
وهذه هي الصفحة، ونحن نشير إلى نفس الصفحة في كل مكان في طرقنا ( methods). هذه هي سمة رابط تسجيل الدخول. هذه هي سمة صندوق إدخال اسم المستخدم، وهذه سمة صندوق كلمة المرور، وهذه سمة زر تسجيل الدخول. هذه هي السمات
Speaker A
التي استخدمتها، وهنا سنحتفظ بجميع المحددات في المُنشئ، والآن يجب أن نكتب طرقنا. الطريقة الأولى التي كتبتها هي الانتقال إلى صفحة تسجيل الدخول، وهنا أشير إلى الصفحة ` this.page.goto` وأمرر الرابط . هذا سيحدث كلما قمت باستدعاء هذه الطريقة من الاختبار الفعلي.
Speaker A
سيؤدي هذا إلى تشغيل تطبيقك، ثم سأقوم بإنشاء طريقة أخرى تسمى طريقة تسجيل الدخول كـ ` async login`.
Speaker A
وهذه ستأخذ معيارين ( parameters). سنقوم بتمرير هذين المعيارين من حالة الاختبار. وما نفعله بالضبط في هذا هو أننا يجب أن نصل أولاً إلى هذه الصفحة.
Speaker A
لذا ` await this.page.locator` وقد التقطنا السمة بالفعل في هذا المتغير ، لنقل رابط تسجيل الدخول. لذا نحن نشير هنا إلى ` login link.click` وهو إجراء، النقر هو إجراء. سيؤدي هذا إلى تنفيذ إجراء النقر على تسجيل الدخول. هذا العنصر، سمة هذا
Speaker A
العنصر يتم الاحتفاظ بها في المُنشئ. نفس الشيء بالنسبة للعبارة الثانية await this.page.locator ومدخل اسم المستخدم. إذن ما هذا؟ هذه سمة لعنصر مربع الإدخال حيث يجب عليك ملء اسم المستخدم. اسم المستخدم هذا يأتي مرة أخرى من الاختبار.
Speaker A
لاحقاً سنقوم بتمرير اسم المستخدم هذا إلى طريقة تسجيل الدخول. ومرة أخرى سنشير إلى عنصر آخر await this.page.locator وهنا مدخل كلمة المرور . إذن هذا هو في الواقع مدخل كلمة المرور. هذه سمة. لذا يجب أن نمرر هذا داخل طريقة تحديد
Speaker A
الموقع. سيقوم هذا بتحديد العنصر وملء كلمة المرور وأخيراً تحديد زر تسجيل الدخول ثم تنفيذ إجراء النقر.
Speaker A
أي عناصر حددناها في المُنشئ، نحاول التفاعل معها في طريقة تسجيل الدخول. حاليًا قمت بإنشاء طريقتين مختلفتين. واحدة لفتح الصفحة، والأخرى لتسجيل الدخول. حسناً.
Speaker A
وهذه هي العناصر. هذه هي الطريقة التي يمكننا بها ببساطة إنشاء فئة كائن الصفحة . بمجرد إنشاء فئة كائن الصفحة هذه، يجب أن نجعلها متاحة للوصول إليها من فئات أو اختبارات أخرى. لذا ما نحتاج للقيام به هو استخدام شيء يسمى
Speaker A
exports.loginPage. يجب أن نقوم بتصدير الفئة بنفس الاسم الذي استخدمناه هنا. يجب أن نقوم بتصدير هذه الفئة.
Speaker A
عندما نقوم بتصدير هذه الفئة سنتمكن من استيرادها في ملف آخر. إذا لم نتمكن من التصدير أو إذا لم تقم بتصدير هذه الفئة، فلا يمكننا استيرادها في ملف آخر. لذا فإن إنشاء الفئة وحدها ليس كافياً. يجب أن نقوم بتصدير هذه الفئة.
Speaker A
لذلك نحتاج لكتابة هذه العبارة exports.loginPage تساوي ثم يمكننا البدء بكتابة الفئة. ما الذي تحتويه فئة كائن الصفحة؟ إنها تحتوي على مُنشئ. يحتوي المُنشئ على جميع سمات العناصر، ثم يمكننا كتابة طرق الإجراء المقابلة، وفي تلك الطرق يمكننا استخدام هذه السمات لتحديد
Speaker A
العنصر. في الواقع، أين نقوم بالتحديد؟ نحن نحدد داخل طريقة الإجراء نفسها. هنا نقوم بالتحديد ثم تنفيذ الإجراء في هذه الطريقة. حسناً.
Speaker A
لنفترض أنه حدث غداً أي تغيير في خصائص السمات أو العناصر. يمكننا تعديلها مباشرة هنا في المُنشئ . حسناً. لذا لا نحتاج إلى لمس أي طرق إجراء ولا نحتاج إلى لمس أي حالة اختبار. هذه هي الطريقة التي يمكننا بها ببساطة إنشاء فئة
Speaker A
كائن الصفحة. هذه هي فئة كائن الصفحة لصفحة تسجيل الدخول. الآن دعونا نحاول استخدام صفحة تسجيل الدخول هذه ومحاولة إنشاء اختبار جديد. الآن سأعود إلى ملف test.spec.js، حالياً قمت بإنشاء فئة كائن صفحة لتسجيل الدخول.
Speaker A
الآن أحاول أتمتة اختبار تسجيل الدخول باستخدام فئة كائن الصفحة. حسناً. الآن دعونا نرى كيف يمكننا أتمتة تسجيل الدخول باستخدام فئة كائن الصفحة. أول شيء يجب القيام به عند بدء كتابة الاختبار هو استيراد الفئة، لأننا قمنا بالفعل بإنشاء وتصدير فئة كائن صفحة
Speaker A
تسجيل الدخول، ونحتاج لاستيرادها هنا. لاستيراد فئة خارجية، يمكننا استخدام الكلمة المفتاحية import وتحديد اسم الفئة login page بين أقواس، ونستوردها من المسار الحالي للمشروع عبر مجلد pages واسم الملف هو login page. إذا نظرت هنا تحت المجلد pages في
Speaker A
المشروع، ستجد أن login page هي فئة كائن الصفحة. لذا يجب أولاً استيراد تلك الفئة الخارجية، ومن ثم فقط سنتمكن من الوصول إلى جميع الطرق بداخلها. حسناً. الآن كالمعتاد، قمنا بإنشاء طريقة اختبار واحدة وقمنا بتمرير وصف لها وتجهيز الصفحة
Speaker A
. الآن دعونا نحاول تسجيل الدخول باستخدام فئة كائن الصفحة. حسناً. للقيام بذلك، أولاً وقبل كل شيء، لقد حصلنا بالفعل على عنصر الصفحة هذا، أليس كذلك؟ للوصول إلى الطرق الموجودة في صفحة تسجيل الدخول، سيتم استدعاء المشيد تلقائياً عند إنشاء
Speaker A
الكائن. لذا بمجرد إنشاء كائن، سنتمكن فقط من الوصول إلى هذه الطرق. انتقل إلى اختبار pom، وهنا دعونا نحاول إنشاء كائن من صفحة تسجيل الدخول.
Speaker A
كيف يمكننا إنشاء ذلك ببساطة؟ يمكننا استخدام الكلمة المفتاحية new. سننشئ كائناً جديداً من فئة login page، وسأعرف متغيراً باسم login.
Speaker A
حسناً، ببساطة عليك إنشاء كائن. لذا ستقوم new login page بإنشاء كائن يُشار إليه بواسطة المتغير الذي يسمى login.
Speaker A
الآن باستخدام هذا الكائن، سنتمكن من الوصول إلى الطرق من فئة كائن الصفحة. ما هي الطريقة الأولى التي نحتاج للوصول إليها؟ الانتقال إلى صفحة تسجيل الدخول. سيؤدي ذلك تلقائياً إلى تشغيل تطبيقك في المتصفح، وبعد ذلك علينا فقط استدعاء هذه
Speaker A
الطريقة المسماة login. وعند استدعاء هذه الطريقة، يجب أن نمرر اسم المستخدم وكلمة المرور، ليتم تنفيذ عملية تسجيل الدخول.
Speaker A
بالعودة هنا، باستخدام هذا الـ login، وعند استخدام هذا الـ login، استخدم await مع كائن الـ login متبوعاً بنقطة. الآن يمكنني هنا الوصول إلى الطريقة login.go to login page.
Speaker A
لا نحتاج لتمرير أي معامل، لذا سيتمكن هذا من الانتقال إلى صفحة تسجيل الدخول. سيقوم هذا باستدعاء الطريقة من فئة كائن الصفحة (page object class). هذا هو الجزء الذي سيتم تنفيذه وسيؤدي إلى تشغيل الصفحة. بعد ذلك، هناك شيء آخر نحتاج إلى
Speaker A
فهمه. لذا، عندما تنشئ كائناً هنا لكائن صفحة تسجيل الدخول، فإن صفحة تسجيل الدخول تحتوي على دالة بناء ( constructor)، أليس كذلك؟ سيتم استدعاء دالة البناء هذه تلقائياً، وفي وقت الاستدعاء هي تتوقع كائن صفحة أو تجهيزة (fixture). لذا نحتاج إلى تمرير ذلك
Speaker A
هنا. أياً كانت الصفحة التي نشير إليها هنا، يجب علينا تمرير نفس الشيء داخل دالة البناء. حسناً. الآن نستدعي صفحة تسجيل الدخول من كائن تسجيل الدخول. وما الذي نحتاج لاستدعائه أيضاً بمجرد فتح التطبيق؟ علينا استدعاء طريقة أخرى من فئة كائن الصفحة. لنقل
Speaker A
طريقة تسجيل الدخول. سأقوم باستدعائها عن طريق تمرير اسم المستخدم وكلمة المرور. لذا لاستدعاء تلك الطريقة ببساطة نستخدم await login.login مجدداً، ونحتاج لتمرير معاملين. أنا أمرر اسم المستخدم، وهذا هو اسم المستخدم الخاص بي، ثم سأمرر كلمة المرور. حسناً، سيقوم هذا بإجراء
Speaker A
عملية تسجيل الدخول. بمجرد تقديم اسم المستخدم وكلمة المرور، نقوم باستدعاء الطريقة من فئة كائن الصفحة. الآن ستنتقل إلى فئة كائن الصفحة وسيتم تنفيذ طريقة تسجيل الدخول هذه وسينجح الدخول.
Speaker A
حسناً، الآن عد واحفظ الملف ولنحاول التنفيذ. هنا في تسجيل الدخول لم نحدد أي عناصر ولم نقم بأي إجراء على أي عناصر.
Speaker A
ببساطة لقد استدعينا تلك الطرق من فئة كائن الصفحة. حسناً. بالمثل إذا أردت الإشارة إلى نفس عناصر صفحة تسجيل الدخول في حالة اختبار أخرى، عليك فعل الشيء نفسه. لذا في كل مرة لا تحتاج لتحديد العناصر ولا تحتاج للقيام بالإجراءات مجدداً.
Speaker A
بمجرد إنشاء عناصر صفحة تسجيل الدخول وطرق الإجراءات، يمكننا إعادة استخدامها في حالات اختبار متعددة. تلك هي الميزة الرئيسية لاستخدام نمط نموذج كائن الصفحة (Page Object Model). الآن عد إلى ملف promptspect js الخاص بك.
Speaker A
دعني أحاول تنفيذ هذه الخطوات فقط. يفتح صفحة تسجيل الدخول. اذهب إلى صفحة تسجيل الدخول وقم بإجراء الدخول. الآن احفظ الملف، وبعد ذلك سيتم التنفيذ بسرعة كبيرة.
Speaker A
لذا سأضع أيضاً بعض وقت الانتظار حتى أتمكن من قول await page.waitForTimeout ويمكنني وضع 3 ثوانٍ مثلاً.
Speaker A
حسناً، أنا أنتظر هنا مؤقتاً في الكود فقط لأرى ما إذا كان الإجراء قد تم بشكل صحيح أم لا. احفظ الملف ثم نفذ الاختبار. نحن نحاول دائماً تنفيذ الاختبار وليس فئة كائن الصفحة. نحن نشير إلى فئة كائن الصفحة من الاختبار. إذًا
Speaker A
اختباري هو pom test.spec.js والمشروع هو chromium وأحاول تشغيله في وضع الرأس. حسنًا، لنحاول تشغيل هذا. حسنًا، الآن فتح شاشة تسجيل الدخول وقام بتسجيل الدخول بنجاح. الآن تم إغلاق صفحتي. حسنًا، الأمر بسيط للغاية.
Speaker A
لذلك قمنا بإنشاء فئة كائن صفحة جديدة، ومن خلال هذا الكائن نحاول استدعاء جميع الطرق من فئة كائن الصفحة، وعلينا تكرار نفس الشيء للصفحة الرئيسية وكذلك عربة التسوق. حسنًا. بمجرد تسجيل الدخول بنجاح إلى التطبيق، فإن الإجراء التالي الذي يتعين علينا القيام به
Speaker A
هو اختيار المنتج من الصفحة الرئيسية. لذا، دعني أحاول تسجيل الدخول مرة أخرى. وأنا أقوم فقط بتسجيل الدخول إلى التطبيق.
Speaker A
وبمجرد فتح الصفحة الرئيسية، أريد هنا تحديد أحد المنتجات، حسنًا؟ لذا يجب أن أختار أحد المنتجات، وبمجرد النقر فوق هذا المنتج، ستظهر لك شاشة أخرى، وهنا نحتاج إلى النقر فوق "إضافة إلى عربة التسوق"، ثم سينتقل إلى صفحة العربة. حسنًا. إذًا ما
Speaker A
نحتاج إلى القيام به الآن هو إنشاء فئة كائن صفحة أخرى لهذه الصفحة الرئيسية بالتحديد. في هذه الصفحة الرئيسية توجد منتجات متعددة. لذا نحتاج إلى الحصول على كل هذه المنتجات، وأي منتج نريد اختياره سنتمكن من اختياره.
Speaker A
لذلك نحتاج هنا إلى كتابة طريقة مناسبة، ويجب أن تكون طريقة واحدة قادرة على اختيار أي منتج تريده.
Speaker A
نحن لا نكتب طرقًا متعددة لمنتجات متعددة. سنكتب طريقة واحدة فقط، وستأخذ تلك الطريقة اسم المنتج كمعامل، وأيًا كان الاسم الذي مررناه إلى تلك الطريقة. سيتم اختيار المنتج المحدد وإضافته إلى عربة التسوق. سأوضح لك الآن كيفية إنشاء فئة كائن
Speaker A
صفحة أخرى للصفحة الرئيسية. حسنًا. الآن عد إلى محرر VS Code، وأنا أغلق صفحة تسجيل الدخول والاختبار هذه.
Speaker A
الآن إذا نظرت هنا، فقد قمت بإنشاء فئة كائن صفحة أخرى وهي homepage.js. وهذه فئة كائن صفحة أخرى. لذا هنا اسم صفي هو homepage. وكما هو معتاد، علينا إنشاء مُنشئ واحد. في المُنشئ، آخذ أداة الصفحة (page fixture) كمعامل. الآن أقوم
Speaker A
بتعيين متغير الصفحة المحلي إلى متغير الفئة. وهذا الـ "this" يمثل الفئة في كل مرة.
Speaker A
لذا فإن متغير this.page هذا أشير إليه في كل اختبار أو كل طريقة. حسنًا. الآن لاحظ عدد العناصر التي نحتاجها هنا. في البداية قد لا تضيف كل العناصر.
Speaker A
لنفترض أنك ترى في هذه الصفحة الرئيسية عناصر متعددة. عناصر كثيرة، ولكن في المرحلة الأولى ليس عليك إضافة كل العناصر . فبناءً على حالة الاختبار، نحتاج لعدد معين من العناصر للتفاعل معها. لذا، سنضيف فقط تلك العناصر المطلوبة أولياً إلى
Speaker A
فئة "كائن الصفحة"(Page Object class). ومع تقدم الاختبار، وبافتراض أنك تقوم بأتمتة حالات اختبار متعددة، يمكنك الاستمرار في إضافة المزيد من العناصر وطرق التنفيذ إلى فئة " كائن الصفحة" كلما دعت الحاجة. حسناً. لذا، في البداية، أقوم بإضافة العناصر المطلوبة
Speaker A
لاختبارنا فقط. حالياً ، أريد إضافة طريقة واحدة تأخذ اسم المنتج كمعامل، وبناءً عليه ستقوم باختيار المنتج وإضافته إلى عربة التسوق. حسناً.
Speaker A
العناصر التي أستخدمها حالياً هنا هي مسار (XPath) لمنتجات متعددة. سأقوم بكتابة بعض المنطق البرمجي هنا. لنفترض أنني سأنشئ طريقة تسمى " إضافة منتج إلى العربة ". ما ستفعله هذه الطريقة فعلياً هو أخذ اسم المنتج كمعامل، وهذا المعامل يجب أن
Speaker A
نمرره عبر حالة الاختبار. حسناً. داخلياً، ما ستفعله هو أنه عند تمرير اسم المنتج لهذه الطريقة، ستحصل هذه الطريقة على كافة المنتجات ثم تبحث عن منتجنا. فمثلاً، إذا أرسلت "Nexus 6" كمنتج وأردت اختياره، ستقوم هذه الطريقة بجلب اسم المنتج، وتخزين كافة
Speaker A
المنتجات في متغير، ثم قراءة كل منتج على حدة ، وإذا تطابق اسم المنتج تماماً مع الاسم الذي مررناه، فسيتم اعتماده. إذا كان اسم المنتج مساوياً لمحتوى نص المنتج، فالمحتوى النصي هو ما سنحصل عليه من العنصر. إذا كان متطابقاً، فسنضغط
Speaker A
على المنتج وننهي الحلقة التكرارية. إذا لم يكن متطابقاً، فسنحصل على منتج آخر من نفس الصفحة ونفحص اسمه مجدداً. إذا تطابق الاسم، فسنضغط على المنتج. هذه الحلقة التكرارية ستتكرر مع منتجات متعددة. سواء كان لديك خمسة منتجات مختلفة أو عشرة، وبناءً على اسم
Speaker A
المنتج الذي مررته، ستتكرر العملية للمقارنة بين اسم منتجك والمنتجات الأخرى، وعند حدوث تطابق، سيتم الانتقال للضغط على ذلك المنتج تحديداً. إذاً هذا هو المنطق الذي يتعين علينا تنفيذه. لذا فنحن نحتاج هنا إلى ثلاثة عناصر فقط، ومحدد "Xpath" هذا
Speaker A
سيتطابق مع جميع المنتجات الموجودة في الصفحة. الآن إذا عدت للخلف، فلنحاول الفحص والانتقال إلى "SelectorHub" وإذا قمت بلصق مسار " Xpath" الذي أنشأته.
Speaker A
يمكننا الآن النظر هنا ، فهذا المسار يتطابق مع عناصر متعددة، أي أسماء منتجات متعددة.
Speaker A
إذن هناك تسعة منتجات إجمالاً في الصفحة. وجميع المنتجات التسعة تتطابق مع مسار "Xpath" هذا. وباستخدام هذا المسار، أقوم بالتقاط جميع المنتجات الموجودة في الصفحة. لذا أقوم بتخزين هذه السمة في قائمة المنتجات، وهذا زر آخر. بمجرد النقر على أي من المنتجات،
Speaker A
سينتقل إلى سلة التسوق ، وهذا هنا هو زر. وهذا ينتمي أيضاً إلى الصفحة الرئيسية. لذا أقوم أيضاً بإضافة عنصر "إضافة إلى السلة" هنا. هذا هو العنصر.
Speaker A
حسناً. هذا هو الزر في الواقع. إذاً زر "إضافة إلى السلة" وهذه هي السلة. بمجرد إضافتها إلى السلة، إذا انتقلت إلى نافذة السلة أو صفحة السلة، يجب عليك النقر على رابط السلة هنا. بمجرد النقر على هذا الرابط، ستنتقل إلى السلة. حسناً. هذه
Speaker A
هي العناصر الثلاثة التي تنتمي إلى الصفحة الرئيسية. لذا، أقوم بإضافة تلك العناصر في المُنشئ، وأقوم بالتقاط جميع المنتجات باستخدام هذه السمة. وبهذه السمة، أحصل على زر " إضافة إلى السلة" وهذا ؛ وهذا في الأساس هو معرف "ID". ومن خلاله،
Speaker A
أحصل على عنصر السلة. ثلاثة عناصر؛ في الوقت الحالي، قمت بإضافة هذه العناصر الثلاثة فقط. مستقبلاً، إذا أردت الإضافة، يمكنك إضافة المزيد من العناصر. الآن، هذه هي الطريقة الفعلية التي كتبناها: واحدة لإضافة المنتج إلى السلة. ما ستفعله هذه الطريقة هو
Speaker A
أنها ستأخذ اسم المنتج كمعامل. لذا عندما أستدعي هذه الطريقة، يجب علينا تمرير اسم المنتج من حالة الاختبار، وسوف تشير داخلياً إلى ذلك.
Speaker A
وعلامة الدولار المزدوجة تمثل عناصر متعددة. كلما أردت الحصول على جميع العناصر في شكل مصفوفة ، علينا استخدام "await this page". ما المقصود بـ " this.page" هنا؟ إذن هذا "page . $" مع "this.product list"، وقائمة المنتجات هذه ليست سوى سمة. لذا يجب
Speaker A
أن نمرر المحدد هنا، أي السمة التي نخزنها في المتغير الذي أقوم بتمريره هنا. لقد حصلنا على قائمة المنتجات بالكامل، وبمجرد الحصول على جميع المنتجات من الصفحة الرئيسية، علينا قراءة كل منتج على حدة في هذا المتغير، والحصول على محتوى النص، ومقارنته
Speaker A
باسم منتجنا. إذا حدث تطابق، اضغط على المنتج. إذا لم يكن هناك تطابق، اذهب مجدداً واحصل على منتج آخر في هذا المتغير. قم بالمطابقة مرة أخرى.
Speaker A
إذا حدث تطابق، اضغط عليه وأنهِ الحلقة التكرارية. سيتكرر هذا عدة مرات لجميع المنتجات، وكلما تمت مطابقة منتجك، سيقوم بالضغط عليه. وبعد ذلك ، ماذا يحدث بمجرد الضغط على هذا المنتج؟ على سبيل المثال، أنا أضغط على المنتج هنا، وبمجرد الضغط عليه،
Speaker A
ستظهر لك هذه الأيقونة : "إضافة إلى السلة". بمجرد الضغط على " إضافة إلى السلة" ستظهر لك نافذة تنبيه.
Speaker A
يجب علينا إغلاق نافذة التنبيه هذه. حسناً. كيف تتعامل مع نافذة التنبيه؟ لقد رأينا بالفعل في فيديوهاتنا السابقة كيفية التعامل مع نافذة التنبيه. لذا علينا تطبيق نفس المفهوم.
Speaker A
أولاً نحتاج للحصول على مربع الحوار هذا، ثم يمكننا قبوله، وبعدها يجب الضغط على " إضافة إلى السلة". لهذا نحتاج لكتابة عبارة أخرى هنا، وهذا هو الجزء الخاص بها. هذه هي الطريقة التي يمكننا بها التعامل مع التنبيه، باستخدام await
Speaker A
this.page.on وأي حوار يظهر علينا التقاطه بشكل غير متزامن مع دالة السهم. إذا تمت إضافة رسالة الحوار، فما علينا فعله هو إغلاق نافذة التنبيه، ونحتاج لكتابة هذا الكود أولاً ثم الضغط على زر "إضافة إلى السلة". حسناً. هذه هي نفس الطريقة مجدداً
Speaker A
للتعامل مع التنبيه. في الفيديوهات السابقة شرحت بالفعل كيفية التعامل مع التنبيه. نفس الكود هنا. بمجرد ظهور الحوار يجب علينا التقاطه، وإذا احتوى الحوار على كلمة "تمت الإضافة"، علينا إغلاقه باستخدام "قبول "، ثم الضغط على زر " إضافة إلى السلة". هذه
Speaker A
الطريقة تحديداً ستجد المنتج بناءً على الاسم الذي قمنا بتمريره. ستجد المنتج على الصفحة. ثم ستضغط على المنتج. ثم ستضغط على "إضافة إلى السلة".
Speaker A
وبمجرد الانتهاء من هذه الخطوة واكتمال العملية، سيكون المنتج متاحاً في نافذة السلة. وهذه صفحة أخرى. حسناً. وقد أنشأت طريقة أخرى هنا.
Speaker A
"اذهب إلى السلة"، لأنه بمجرد إضافة منتجك للسلة ورغبتك في رؤيته ، نحتاج للضغط على قائمة السلة. إذا عدت للتطبيق هنا، توجد قائمة تسمى "السلة" في الأسفل. بمجرد الضغط على السلة، سنتمكن من الانتقال إلى صفحة السلة. هذه هي صفحة
Speaker A
السلة. حسناً. لذلك قمنا بالفعل بإنشاء طريقة أخرى تسمى الانتقال إلى عربة التسوق. وهنا أشير إلى ذلك العنصر. عربة التسوق هذه تعني أننا قمنا بإنشاء هذا المتغير بالفعل ونحن نشير إليه بالنقر.
Speaker A
حسناً. لقد قمت بإنشاء طريقتين في المجموع. الأولى هي إضافة المنتج إلى عربة التسوق. هذه طريقة واحدة. طريقة أخرى هي الانتقال إلى عربة التسوق. حسناً. هاتان هما الطريقتان اللتان تنتميان إلى الصفحة الرئيسية. أليس كذلك؟ الآن دعونا نحسن الكود باستخدام فئة كائن
Speaker A
الصفحة هذه. دعني أحفظ الملف وأعود إلى الاختبار. دعني أفتح ملف pom test spec.js. لقد انتهينا بالفعل من تسجيل الدخول. الآن دعني أجرب الصفحة الرئيسية. بمجرد فتح صفحتك الرئيسية. فما الذي نحتاج إلى القيام به الآن؟ نحتاج أولاً إلى إنشاء كائن للفئة.
Speaker A
عندها فقط سنتمكن من الوصول إلى كل هذه الطرق. لذا، اذهب إلى pom test spec.js، وهنا كيف تنشئ كائناً باستخدام الكلمة المفتاحية new: new homepage. وكلما قمت بإنشاء كائن لذلك، نحتاج إلى تمرير عنصر الصفحة، لأن المنشئ سيوسع الصفحة. ثم أقوم
Speaker A
بتخزين ذلك الكائن والإشارة إليه بمتغير ؛ لنسمه home: const home. الآن باستخدام هذا الكائن يجب أن نكون قادرين على استدعاء كل طريقة من فئة كائن الصفحة. يمكنني ببساطة قول await home.add product to cart.
Speaker A
الآن أي منتج تريد إضافته هنا هو أنني أريد تمرير اسم المنتج . لذا هناك منتجات متعددة موجودة. إذا عدت إلى هنا. في هذا يمكنك تمرير أي اسم.
Speaker A
حسناً. دعني أمرر شيئاً يسمى Nexus 6. هذا هو المنتج الذي أريد تمريره فقط. وهنا أقوم فقط بتمرير اسم المنتج . لذا await home.add product to.
Speaker A
ما ستفعله هذه الطريقة هو أنها ستستدعي طريقة إضافة المنتج إلى عربة التسوق من فئة كائن الصفحة، وهنا ستستقبل المنتج ثم ستجد كل المنتجات من الصفحة وأي منتج يطابق الاسم ستذهب وتضغط عليه. بعد النقر على المنتج، سيعطيك زر إضافة إلى
Speaker A
عربة التسوق. سيؤدي هذا إلى تنفيذ الإجراء وسيقوم تلقائياً بإغلاق نافذة التنبيه ، ومن ثم سيكون المنتج متاحاً في عربة التسوق . بعد ذلك ماذا نحتاج أن نفعل بمجرد النقر على إضافة إلى عربة التسوق، نحتاج إلى الذهاب إلى نافذة عربة
Speaker A
التسوق وهي صفحة مختلفة. للانتقال إلى صفحة عربة التسوق، يجب علينا استدعاء طريقة الانتقال إلى عربة التسوق. بمجرد الانتهاء، ننتقل الآن إلى الطريقة التالية.
Speaker A
هذه الطريقة تختار المنتج تلقائياً وتضيفه إلى عربة التسوق. الآن الطريقة التالية التي نحتاج لاستدعائها هي الانتقال إلى صفحة سلة التسوق الرئيسية.
Speaker A
يمكننا استخدام await من نفس فئة كائن الصفحة الرئيسية، واستدعاء دالة الانتقال للسلة. حسناً، يمكنك ببساطة الاستدعاء بعد إضافة المنتج للسلة، حيث سيستغرق الأمر بضع ثوانٍ. لذا سأنتظر لبعض الوقت هنا حتى يتم الأمر بشكل أسرع.
Speaker A
سأستخدم انتظاراً للمهلة الزمنية. سأضع مهلة زمنية بسيطة. لنقل إن 3 ثوانٍ كافية. والآن سأنتقل إلى السلة. حسناً. إذاً، انتهينا من كافة الأنشطة على الصفحة الرئيسية. لقد بدأنا من صفحة تسجيل الدخول ثم انتقلنا إلى الصفحة الرئيسية. في الصفحة الرئيسية اخترنا
Speaker A
المنتج وأضفناه للسلة ثم انتقلنا إلى السلة. إذاً هذا هو الرابط الفعلي للانتقال للسلة. وهذا سينقلنا إلى صفحة السلة. الآن ما نحتاجه هو الذهاب إلى صفحة السلة. هذه الطريقة ستنتقل تلقائياً إلى السلة.
Speaker A
بمجرد الانتهاء، الخطوة التالية هي الذهاب للسلة والتحقق من إضافة المنتج بنجاح . ما هي العناصر التي نحتاجها؟ على سبيل المثال، نحن انتقلنا بالفعل إلى السلة. في السلة يوجد جدول هنا.
Speaker A
في هذا الجدول سيتم إضافة جميع المنتجات. الآن نحتاج للتحقق مما إذا كان منتجنا قد أضيف بنجاح هنا أم لا.
Speaker A
هذه صفحة مختلفة تماماً. لذا بالنسبة لهذه الصفحة بالتحديد ، علينا إنشاء فئة كائن صفحة أخرى.
Speaker A
لنسمّها cart page.js. لقد أنشأت بالفعل فئة كائن صفحة هنا. cart page.js. دعني أحفظها. والآن اذهب إلى cart page.js. هذه فئة كائن صفحة أخرى. حسناً.
Speaker A
كم عدد العناصر التي نحتاجها هنا؟ عنصر واحد فقط. وما هو ذلك؟ قد يكون لديك عدد غير محدود من المنتجات المضافة للسلة. لكن هدفنا هنا هو التحقق مما إذا كان منتجي قد أضيف بنجاح للسلة أم لا. كيف يمكننا التحقق
Speaker A
من ذلك؟ أولاً، نحتاج إلى التقاط جميع المنتجات. على سبيل المثال، دعني أحاول إضافة منتج آخر أيضاً.
Speaker A
الآن قمت بإضافة منتج آخر. يمكننا الآن رؤية أنه قد يكون لديك منتجات متعددة في الجدول. هذا في الأساس جدول ويب. قد يكون لديك منتجات متعددة. الآن ما نحتاجه هو معرفة هل منتجنا موجود في هذا الجدول أم لا؟ علينا
Speaker A
التحقق من ذلك. لذا نحتاج لكتابة مسار X path مخصص يمكننا من خلاله التقاط كافة المنتجات من الجدول. ثم يتعين علينا تكرار المرور على كل منتج ومطابقته في الوقت ذاته مع منتجنا المتوقع. لذا نحتاج إلى كتابة منطق برمجي لذلك. إذًا، ما
Speaker A
هو عدد العناصر التي نحتاجها؟ سنكتب مسار XPath عامًا لجلب كافة المنتجات من هذا الجدول. حسنًا. لقد كتبت مسار XPath هذا، وإذا نظرت إليه، دعني أفحصه. سأذهب إلى SelectorHub وأتحقق من مسار XPath هذا، وهو يطابق ثلاثة عناصر تمامًا.
Speaker A
حاليًا، لدي ثلاثة منتجات فقط مضافة إلى الجدول. لذا فهو يطابق العناصر الثلاثة. لو كان لدي عدد أكبر من المنتجات، فسيقوم مسار XPath نفسه بمطابقة جميع المنتجات تلقائيًا. الآن أحاول استخدام مسار XPath هذا لالتقاط كافة معلومات وأسماء المنتجات، ثم
Speaker A
سأطابقها مع المنتج الذي أضفته في الخطوة السابقة. ببساطة، يمكنك الانتقال إلى صفحة سلة التسوق في Java.
Speaker A
هذه فئة أخرى لكائن الصفحة (Page Object Class). لقد أنشأت بالفعل مُنشئًا (constructor) داخلها. يمكنك إلقاء نظرة، حيث نمرر الصفحة هنا، وهذا مسار XPath يطابق كل المنتجات في الجدول. أقوم بتخزين ذلك في متغير. هذه مجرد سمة. حسنًا، باستخدام مسار XPath هذا، يجب أن
Speaker A
أكون قادرًا على العثور على جميع المنتجات. لقد قمت بذلك داخل إحدى الدوال . يمكنك ببساطة النظر إلى هذه الدالة. ما فعلته بالضبط في هذه الدالة هو التحقق من المنتج في السلة. هذه هي الدالة التي أنشأتها، ويجب علينا الحصول على اسم المنتج
Speaker A
الذي أضفناه إلى السلة . نريد العثور على المنتج نفسه في صفحة السلة. ستقوم هذه الدالة بإرجاع اسم المنتج والحصول عليه.
Speaker A
وهذه العبارة المحددة ، await this dot page...ما هو this dot page؟ هذا هو، this dot page.
Speaker A
دالة dollar لجلب عناصر ويب متعددة و...this dot number of products، حيثما أستخدم this، فهي تشير إلى متغير الفئة، حسنًا. هذا المتغير يحتوي بالفعل على مسار XPath الخاص بعدد المنتجات الذي مررته هنا. إذًا، سيعيد هذا أساسًا كل المنتجات التي تمت إضافتها إلى
Speaker A
السلة. يحتوي هذا المتغير على كل المنتجات المضافة للسلة، وما فعلته هنا هو الحصول على كل منتج باستخدام حلقة التكرار for. سأكرر المرور على كل منتج في هذا المتغير، وأقوم أيضًا بطباعة محتوى المنتج، أي اسم المنتج . إذًا، كيف نحصل على
Speaker A
المحتوى من المنتج؟ المنتج هنا يعني عنصر الويب، لذا يمكنك ببساطة كتابة product.textContent وهذا سيطبع الرسالة. بعد ذلك، أقوم بمقارنته في الواقع. لذا، أي اسم منتج نمرره يجب أن يساوي اسم المنتج المضاف إلى الجدول. من بطاقة المنتجات، هذا يمثل منتجات متعددة في
Speaker A
الجدول. نحن نحصل على اسم المنتج الأول، وإذا تطابق، نعيد القيمة "صحيح"(true) وننهي الحلقة. إذا لم يتطابق، ستحصل على منتج آخر وتقوم بالمقارنة. وهكذا، إذا كان هناك عدد "n" من المنتجات المضافة إلى سلة التسوق. نحن نقارن مع كل منتج على حدة،
Speaker A
وحيثما يحدث التطابق نعيد "صحيح" ثم ننهي الحلقة. إذًا، هذه الطريقة المحددة ستحصل على اسم المنتج وتتحقق مما إذا كان متاحًا في السلة أم لا.
Speaker A
إذا كان متاحًا، تعيد " صحيح". إذا لم يكن متاحًا، فإنه ببساطة يخرج. حسنًا. إذًا ستتوقف الحلقة. إذا كان متاحًا، فسيعيد " صحيح". إذا لم يكن متاحًا، ستتكرر الحلقة ولن يعيد أي شيء. حسنًا. إذًا هذه هي الطريقة التي يتعين
Speaker A
علينا إنشاؤها بالإضافة إلى ذلك. إذًا عنصر واحد فقط. إذًا خاصية واحدة تطابق عناصر متعددة أو منتجات متعددة مضافة إلى السلة. حسنًا. الآن عُد إلى الاختبار الرئيسي. احفظ ذلك وانتقل إلى pom test.spec.js.
Speaker A
وهنا قمنا بالتفاعل مع صفحة تسجيل الدخول. ثم تفاعلنا مع الصفحة الرئيسية وأضفنا المنتج للسلة، وذهبنا لصفحة السلة والآن نحتاج للتحقق. لذا، للوصول إلى الطريقة من صفحة السلة، علينا إنشاء كائن من صفحة السلة. إذًا كيف ننشئ كائنًا لصفحة السلة؟
Speaker A
يمكنك القيام بذلك هكذا: new cart page. صفحة سلة جديدة (New cart page). عندما تنشئ كائنًا، يجب أن نمرر "page fixture" ونحتاج لإنشاء متغير يسمى cart ونجعله متغيرًا ثابتًا (const).
Speaker A
الآن باستخدام هذا الكائن، يمكننا الوصول إلى الطرق من صفحة السلة. لذا، أنشأنا طريقة واحدة بسيطة. ما يمكننا فعله هو await و cart دوت. await cart dot اسم تلك الطريقة هو check product in cart. حسنًا، إنها لا تظهر. دعني
Speaker A
أتحقق لثانية واحدة. اذهب إلى صفحة السلة. نحتاج لحفظ الملف. حسنًا، لقد قمنا بالفعل بتصدير صفحة السلة. الآن اذهب إلى الملف واحفظ هذا أولاً . نعم. الآن await cart. دوت.
Speaker A
check a product in cart. حسنًا. أعتقد أنه يجب أن يظهر تلقائياً. دعني أتحقق من ذلك. لقد أنشأنا هذه الطريقة مسبقاً، احفظ الملف وهذه هي طريقة التحقق من المنتج في السلة. ثم يتعين علينا تمرير اسم الطريقة.
Speaker A
لذا دعنا نستدعي هذه الطريقة في pom test.spec. إذن cart dot check product in cart.
Speaker A
وهنا يجب أن نمرر اسم المنتج. لذا، المنتج الذي أضفناه، سأتحقق مما إذا كان هذا المنتج نفسه جزءاً من صفحة السلة أم لا. وبعد ذلك، ستعيد هذه الطريقة قيمة صح (true) أو خطأ (false)، أليس كذلك ؟ إذاً، إذا كان
Speaker A
المنتج متطابقاً هنا، فسيعيد ذلك صح أو خطأ، لذا نحتاج لتخزين ذلك في متغير. لذا، أنا أنشئ متغير حالة هنا، ونوع هذا المتغير هو.
Speaker A
constus الآن، سأضع تحقُّقاً (assertion) هنا. أقول، "Expect await status وأن تكون هذه الحالة صحيحة ". حسناً. إذاً هذا هو التحقق. حسناً. بعد الحصول على هذه السلة، سأنتظر أيضاً لبعض الوقت هنا حتى نتمكن من رؤية العملية بدقة.
Speaker A
سأنتظر page dot wait for timeout. يمكنني فقط جعلها 3 ثوانٍ. حسناً. إذاً الآن إذا نظرت إلى الاختبار الفعلي هنا، فأنا أحفظه. نحن نشير إلى ثلاث صفحات مختلفة . صفحة تسجيل الدخول، والصفحة الرئيسية، ثم صفحة السلة. في صفحة تسجيل الدخول، أنشأنا
Speaker A
سيناريو تسجيل الدخول. في الصفحة الرئيسية، وجدنا المنتج وأضفناه إلى السلة. في صفحة السلة، نتحقق مما إذا كان المنتج موجوداً أو متاحاً في السلة بعد إضافته. إذاً قمنا بثلاثة أمور مختلفة من ثلاث صفحات مختلفة.
Speaker A
وإذا نظرت هنا، فهناك ثلاث صفحات أنشأناها: صفحة تسجيل الدخول، والصفحة الرئيسية، وصفحة السلة. في المستقبل إذا أردت إضافة المزيد من العناصر، فلا يزال بإمكانك إضافتها وكذلك المزيد من الطرق . حتى الآن، هذه هي الطرق التي أضفتها في كل فئة كائن صفحة (page
Speaker A
object class). في الصفحة الرئيسية إضافة منتج للسلة، وفي صفحة تسجيل الدخول أنشأت طريقة تسجيل الدخول، وفي صفحة السلة أنشأت طريقة أخرى تسمى التحقق من المنتج في السلة. إذاً، هذه هي فئات كائنات الصفحات الثلاث المختلفة التي أشير إليها في اختبار
Speaker A
واحد، وهو pom test specjs. هذه هي عناصر صفحة تسجيل الدخول، وعناصر الصفحة الرئيسية، ثم السلة، وإذا نظرت هنا في الاختبار الفعلي، فنحن لا نشير إلى أي عناصر ولا ننفذ أي إجراء عليها؛ نحن نعتمد ببساطة كلياً على فئات كائنات
Speaker A
الصفحات. يمكننا الرجوع إلى نفس فئات كائنات الصفحة في حالات اختبار متعددة. حسناً. على سبيل المثال هنا. لصفحة تسجيل الدخول، أنشأت فئة كائن صفحة واحدة.
Speaker A
للصفحة الرئيسية، أنشأت فئة كائن صفحة أخرى. لصفحة عربة التسوق، أنشأت فئة كائن صفحة إضافية.
Speaker A
الآن قمت بإنشاء اختبار واحد. أشرت فيه إلى جميع فئات كائنات الصفحة. لنفترض غداً أنك أنشأت اختباراً آخر، يمكننا الرجوع لنفس فئات كائنات الصفحة. لنفترض أنني أنشأت الاختبار الثالث، يمكنني مجدداً الرجوع لنفس الفئات بالإضافة لإنشاء صفحات أخرى.
Speaker A
إذن، الميزة هنا هي أننا نحقق إمكانية إعادة الاستخدام. هذا يعني بمجرد تحديد العناصر الموجودة في فئات كائنات الصفحة، يمكننا إعادة استخدامها أو الرجوع لنفس العناصر في اختبارات متعددة، وإذا حدث أي تغيير غداً، يمكنك الانتقال مباشرة إلى فئة كائن
Speaker A
الصفحة المعنية وتعديل السمات. تلك هي الميزة الرئيسية لاستخدام نموذج كائن الصفحة. حسناً. الآن لنحاول تنفيذ الاختبار، وقد طبقنا الاختبار بالكامل باستخدام نهج فئة كائن الصفحة أو نموذج كائن الصفحة. حسناً. لنقم أخيراً بحفظ الملف ونرى ما إذا كان المنتج قد أضيف إلى
Speaker A
عربة التسوق أم لا. التالي ستة، التالي ستة. حالياً لدي منتجات متعددة. لذا دعوني أحذفها. حسناً.
Speaker A
وهناك منتجان آخران. حالياً ليس لدي أي منتجات. حتى لو كان لديك منتجات متعددة، سيكون قادراً على البحث عن المنتج.
Speaker A
حسناً، ليس لدي أي منتجات في تطبيقي. الآن لنحاول تنفيذ اختباري. هنا أقوم بتشغيل اختباري npx playwright test.spec.js وأقوم بتشغيله على متصفح كروميوم في وضع الرأس المرئي. حسناً، الآن يتم تشغيل تطبيقي. تم تسجيل الدخول الآن.
Speaker A
بعد ذلك يقوم بإضافة المنتج. النقر على إضافة إلى المنتج. التعامل مع نافذة التنبيه. ثم في النهاية سيذهب إلى عربة التسوق. نعم. الآن يمكننا أن نرى أنه قد فشل لسبب ما. صفحة عربة التسوق غير محددة.
Speaker A
صفحة عربة التسوق غير محددة. لذا أثناء إنشاء صفحة عربة التسوق، فإنه يعطي خطأ . دعونا نرى لماذا يعطي خطأ. نحن نمرر الصفحة، أليس كذلك؟ دعونا نرى كيف أنشأنا صفحة عربة التسوق. هذا هو اسم صفحتنا في الواقع cart page ونحن نحصل على
Speaker A
الصفحة كتركيبة، وإذا نظرت هنا، نفس صفحة عربة التسوق التي أنشأناها، انتقل إلى التعريف. نعم، أعتقد أن هناك خطأ إملائياً.
Speaker A
حسناً، دعني أنسخ هذا، لقد قمنا بتصديره بالفعل. حسناً، نعم المشكلة هي أننا لم نقم بالاستيراد في الواقع، نعم هذه هي المشكلة. نحن نحاول إنشاء كائن لصفحة عربة التسوق، لكننا لم نقم باستيراده هنا. لقد قمنا باستيراد صفحة تسجيل الدخول والصفحة
Speaker A
الرئيسية فقط. لذا بدون استيراد الفئة، لا يمكننا إنشاء كائن. ولا يمكننا استخدام تلك الأساليب. حسناً، لنحاول استيرادها.
Speaker A
يمكنني القول استيراد (import)، وهنا، صفحة عربة التسوق؛ ومن نقطتين، لتمثيل مشروعنا في مجلد الصفحات، ما هو اسم ملفي؟ صفحة عربة التسوق. حسناً، نحتاج أولاً إلى استيراد ذلك . إذن، بمجرد الاستيراد بنجاح، سنتمكن من إنشاء كائن، وسنتمكن من استدعاء
Speaker A
كافة الأساليب. حسناً، لنحاول التشغيل مرة أخرى؛ لنقل Ctrl Clear. الآن أقوم بتشغيل نفس الأمر. حسناً. الآن أطلق تطبيقي. تسجيل الدخول. الآن أضيف المنتج إلى العربة.
Speaker A
انقر على إضافة إلى العربة لمعالجة نافذة التنبيه. ثم أخيراً سيذهب إلى العربة. وهنا يمكنك رؤية وجود منتجين. نعم. الآن منتجي متاح. لقد تم اجتيازه بنجاح. إذن تم اجتياز التحقق الخاص بي. حسناً. الآن إذا أردت رؤية الخطوات بوضوح في التقرير،
Speaker A
يمكنك تنفيذ هذا الأمر . npx playright show report وقل npx playright show-report. سيوفر لك هذا التقرير. الآن عندما تنظر إلى هذا، انقر عليه. يمكنك الآن رؤية أن كل خطوة قد تم تنفيذها بنجاح، كما قمنا بتفعيل الفيديو.
Speaker A
لذا فإن الفيديو مرفق أيضاً بالتقرير. يمكنك فقط النقر عليه. الآن يمكنك رؤية الفيديو وهو يشغل بالضبط كل ما قمت به خلال الاختبار، كل شيء تم تسجيله، وأخيراً يذهب إلى صفحة العربة ثم يتحقق مما إذا كان المنتج موجوداً في العربة أم
Speaker A
لا. حسناً. ونفس الشيء تمت إضافة مرفق المخرجات القياسية له أيضاً. لذا فهذا مقتطف لستة عناصر. هذا هو اسم المنتج الذي قمنا بتمريره. حسناً. هكذا يمكننا كتابة حالات الاختبار باستخدام نمط نموذج كائن الصفحة . نمط نموذج كائن الصفحة هو نوع من
Speaker A
الأنماط أو الأطر التي نحتفظ فيها بجميع عناصر الصفحة والأساليب في فئة واحدة منفصلة. إذا كان لديك صفحات متعددة في تطبيقك، فسنقوم بإنشاء فئات كائنات صفحة متعددة، وننشئ مجلداً منفصلاً يسمى pages. وفي ذلك المجلد سنقوم بإنشاء صفحات متعددة كهذه. حالياً
Speaker A
أضفت عدداً قليلاً من العناصر المطلوبة لحالة الاختبار الخاصة بي. في المستقبل، إذا احتجت إلى مزيد من العناصر في حالات اختبار أخرى، يمكنك الاستمرار في إضافة سمات وأساليب متعددة. حسناً. هذا نشاط مستمر. وهكذا يمكننا ببساطة كتابة حالات الاختبار باستخدام نموذج كائن
Speaker A
الصفحة. إذًا، الهدف الرئيسي من استخدام هذا النهج هو تحقيق إمكانية إعادة الاستخدام. لسنا بحاجة إلى تحديد العناصر في كل حالة اختبار. بمجرد تحديد العناصر، يمكنك إعادة استخدامها في حالات اختبار متعددة.
Speaker A
هذا هو الهدف الأساسي من استخدام نمط كائن الصفحة، وهو مفهوم مدعوم في بلايرايت أيضًا. حسناً. هذا كل شيء لهذا الفيديو. في الفيديو التالي سنناقش موضوعاً آخر.
Speaker A
شكراً للمشاهدة.
Topics:نموذج كائن الصفحةPage Object ModelPOMPlaywrightأتمتة الاختباراتجافاسكريبتاختبارات واجهة المستخدمSDETQAتصميم الاختبارات











