سيلينيوم هو مجموعة من الأدوات والمكتبات مفتوحة المصدر تسمح لك بالتفاعل مع المتصفحات لأداء عمليات مختلفة مثل إرسال نص، النقر على زر، اختيار القوائم المنسدلة، وما إلى ذلك.
ومع ذلك، هناك سيناريوهات يحدث فيها أن الأوامر الفعلية لـ مشغل سيلينيوم لا تعمل كما هو متوقع، حيث لا يمكن لـ سيلينيوم التفاعل مباشرة مع عناصر الويب. هنا يأتي دور JavaScriptExecutor.
في هذه المدونة، سنناقش JavaScriptExecutor في سيلينيوم وكيفية البدء مع حالات الاستخدام العملية والأمثلة.
ما هو JavaScriptExecutor في سيلينيوم؟
JavaScriptExecutor هو واجهة توفرها سيلينيوم تساعد في تنفيذ أوامر JavaScript. توفر هذه الواجهة طرق لتشغيل JavaScript على النافذة المحددة أو الصفحة الويب الحالية. وهي متاحة لجميع ربطات اللغة المدعومة بواسطة سيلينيوم.
يمكن استخدام JavaScriptExecutor في سيلينيوم مباشرة عن طريق استيراد الحزمة التالية في نصوص اختبار الأتمتة:
org.openqa.selenium.JavascriptExecutor
JavaScriptExecutor في سيلينيوم يوفر طريقتين للتفاعل مع عناصر الويب:
executeScript()
– تنفيذ JavaScript في سياق النافذة أو الإطار المحدد حاليًا في سيلينيوم. سيتم تنفيذ النص كجسم لدالة مجهولة.executeAsyncScript()
– هذا الأسلوب ينفذ مقطعًا من JavaScript بشكل غير متزامن في سياق النافذة أو الإطار المُحدد حاليًا في Selenium. سيتم تنفيذ السكربت كجسم لدالة مجهولة.
ملاحظة: الفرق الرئيسي بين الأساليب executeScript()
و executeAsyncScript()
هو أن السكربت الذي يتم استدعاؤه باستخدام executeAsyncScript()
يجب أن يُشير عن انتهاء التنفيذ باستخدام دالة callback()
.
يتم استخدام استدعاء الأساليب باستخدام executeAsyncScript()
بشكل رئيسي عندما يجب أن يتم تنفيذ تأخير في المتصفح تحت الاختبار أو عندما يجب تزامن الاختبارات داخل تطبيق AJAX.
لماذا استخدام JavaScriptExecutor في Selenium؟
هناك سيناريوهات حيث لا تعمل بعض أوامر WebDriver كما هو متوقع بسبب أسباب متعددة، كما يلي:
- عدم تفاعل Selenium مع عناصر الويب مباشرة
- القيام بإجراءات مثل التمرير إلى العرض، النقر على عناصر الويب التي تكون مخفية وراء الضبابية، أو تعيين قيم في حقول القراءة فقط
- القيام بسلوكيات تخصصية للمتصفح مثل تعديل DOM بشكل ديناميكي
في هذه الحالات، نلجأ إلى JavaScriptExecutor في Selenium.
تقليديًا، نستخدم محددات سيلينيوم مثل الهوية، الاسم، محدد CSS، XPath، إلخ، لتحديد عنصر ويب. إذا لم تعمل هذه المحددات، أو كنت تتعامل مع XPath صعب، في مثل هذه الحالات، يساعد JavaScriptExecutor في تحديد عنصر ويب المطلوب.
هناك حالات يمكن أن لا يعمل فيها طريقة click()
على جميع متصفحات الويب، أو قد تكون عناصر التحكم على الويب تتصرف بشكل مختلف على متصفحات مختلفة. للتغلب على مثل هذه الحالات، يجب استخدام JavaScriptExecutor لتنفيذ إجراء النقر.
كما نعلم، تحتوي المتصفحات على تنفيذ JavaScript بداخلها ويمكنها فهم أوامر JavaScript. لذلك، فهم JavaScriptExecutor في سيلينيوم سيمكننا من أداء مجموعة من العمليات بشكل أكثر كفاءة.
أساسيات JavaScriptExecutor في سيلينيوم
غرض هذا القسم هو تقديم فكرة عالية المستوى حول خطوات تنفيذ JavaScriptExecutor في سيلينيوم. للعرض، سنستخدم لغة البرمجة جافا كلغة برمجة مفضلة.
دعونا نلقي نظرة على الخطوات الرئيسية.
1. استيراد الحزمة المرتبطة بـ JavaScriptExecutor:
import org.openqa.selenium.JavascriptExecutor;
2. استخدام JavaScriptExecutor، إنشاء مرجع للواجهة، وتعيينه لمثيل WebDriver عن طريق تحويل النوع:
JavascriptExecutor js = (JavascriptExecutor) driver;
3. استدعاء طرق executeAsyncScript()
أو executeScript()
. على سبيل المثال، الصيغة لـ executeScript()
معروضة أدناه:
js.executeScript(java.lang.String script, java.lang.Object... args)
عرض توضيحي: استخدام JavaScriptExecutor في سيلينيوم
قبل أن ننظر إلى كيفية استخدام JavaScriptExecutor في سيلينيوم، اتبع هذه الشروط المسبقة:
- إنشاء مشروع Maven جديد باستخدام بيئة IntelliJ IDE
- إضافة تبعية أحدث لمكتبة Selenium WebDriver في ملف pom.xml
- إضافة تبعية أحدث لمكتبة TestNG في ملف pom.xml
سنستخدم موقع LambdaTest eCommerce Playground لعرض عمل JavaScriptExecutor في سيلينيوم من خلال تشغيل الاختبارات على متصفح Chrome المحلي.
سيناريو الاختبار 1
هدفنا هو كتابة كود بسيط لتوضيح مثال باستخدام طريقة executeScript()
باستخدام السيناريو الاختباري التالي.
- الانتقال إلى صفحة تسجيل الدخول للحساب على موقع LambdaTest eCommerce Playground.
- إدخال بيانات تسجيل الدخول الصحيحة والنقر على زر تسجيل الدخول عن طريق تحديد الحقل بحدود حمراء.
- طباعة عنوان الصفحة واسم النطاق.
- التأكد من أن عنوان الصفحة “حسابي” يتم عرضه عند تسجيل الدخول بنجاح.
التنفيذ
أنشئ فئة TestJavaScriptExecutor
جديدة لتنفيذ سيناريو الاختبار. سنقوم أولاً بإنشاء طريقتين في هذه الفئة الاختبارية تسمح لنا بإعداد وإنهاء جلسات Selenium WebDriver بشكل لائق.
لنعلن عن WebDriver
على مستوى الفئة حيث سنحتاج إليه في كلتا الطريقتين، أي الطريقة setup()
لبدء جلسة السائق والطريقة tearDown()
لإنهاء الجلسة بشكل لائق.
public class TestJavaScriptExecutor {
private WebDriver driver;
//...
}
لننشئ طريقة setup()
جديدة ستنشئ نسخة من فئة WebDriver
وتعين التكوين وفقًا لتشغيل الاختبارات على متصفح Chrome المحلي.
public void setup () {
driver = new ChromeDriver ();
driver.manage ()
.window ()
.maximize ();
driver.manage ()
.timeouts ()
.implicitlyWait (Duration.ofSeconds (30));
}
سيقوم هذا الطريقة بفتح متصفح Chrome، وتكبير نافذته، وتطبيق انتظار ضمني لمدة 30 ثانية. سيسمح هذا الانتظار الضمني بتحميل جميع محتويات الموقع بنجاح قبل بدء تنفيذ الاختبار.

public void tearDown () {
driver.quit ();
}
أخيرًا، عند تنفيذ الاختبار، سيتم استدعاء الطريقة tearDown()
التي ستغلق جلسة RemoteWebDriver بشكل لائق.
لنضيف الآن طريقة testJavaScriptExecutorCommand()
في نفس فئة الاختبار لتنفيذ السيناريو الذي ناقشناه.
public void testJavaScriptExecutorCommand () {
driver.get ("https://ecommerce-playground.lambdatest.io/index.php?route=account/login");
JavascriptExecutor js = (JavascriptExecutor) driver;
//....
}
الكود يتصفح صفحة تسجيل الدخول إلى موقع LambdaTest eCommerce Playground. السطر التالي يقوم بتحويل نسخة WebDriver إلى JavascriptExecutor
بحيث يمكن تنفيذ أوامر JavaScript في المتصفح.
WebElement emailAddressField = driver.findElement (By.id ("input-email"));
js.executeScript ("arguments[0].style.border='3px solid red'", emailAddressField);
emailAddressField.sendKeys ("[email protected]");
js.executeScript ("arguments[0].style.border='2px solid #ced4da'", emailAddressField);
بعد ذلك، يحدد الحقل emailAddressField
باستخدام استراتيجية تحديد الـ id
. ثم، يستخدم أمر JavascriptExecutor لتمييز حدود حقل عنوان البريد الإلكتروني بلون أحمر.
WebElement passwordField = driver.findElement (By.id ("input-password"));
js.executeScript ("arguments[0].style.border='3px solid red'", passwordField);
passwordField.sendKeys ("Password123");
js.executeScript ("arguments[0].style.border='2px solid #ced4da'", passwordField);
ثم يتم تحديد حقل كلمة المرور وتمييزه بحدود حمراء. يساعد هذا التمييز في معرفة الخطوات التي يتم تنفيذها أثناء تنفيذ اختبار الأتمتة.
WebElement loginBtn = driver.findElement (By.cssSelector ("input.btn"));
js.executeScript ("arguments[0].style.border='3px solid red'", loginBtn);
js.executeScript ("arguments[0].click();", loginBtn);
بالمثل، يتم تحديد زر تسجيل الدخول باستخدام استراتيجية محدد CSS ويتم تمييزه أيضًا.
String titleText = js.executeScript ("return document.title;").toString ();
System.out.println ("Page Title is: " + titleText);
String domainName = js.executeScript ("return document.domain;").toString ();
System.out.println ("Domain is: " + domainName);
يتم تحديد عنوان الصفحة واسم النطاق بعد ذلك باستخدام JavaScriptExecutor ويتم طباعتهما على وحدة التحكم.
String myAccountHeader = driver.findElement (By.cssSelector ("#content h2")).getText ();
assertEquals (myAccountHeader, "My Account");
أخيرًا، يتم تحديد رأس الصفحة الخاصة بصفحة حسابي، التي يتم عرضها بعد تسجيل الدخول بنجاح، ويتم إجراء تأكيد للتحقق من أنها تعرض النص “حسابي“.
فيما يلي الكود الكامل من فئة TestJavaScriptExecutor
:
public class TestJavaScriptExecutor {
private WebDriver driver;
public void setup () {
driver = new ChromeDriver ();
driver.manage ()
.window ()
.maximize ();
driver.manage ()
.timeouts ()
.implicitlyWait (Duration.ofSeconds (30));
}
public void tearDown () {
driver.quit ();
}
public void testJavaScriptExecutorCommand () {
driver.get ("https://ecommerce-playground.lambdatest.io/index.php?route=account/login");
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement emailAddressField = driver.findElement (By.id ("input-email"));
js.executeScript ("arguments[0].style.border='3px solid red'", emailAddressField);
emailAddressField.sendKeys ("[email protected]");
js.executeScript ("arguments[0].style.border='2px solid #ced4da'", emailAddressField);
WebElement passwordField = driver.findElement (By.id ("input-password"));
js.executeScript ("arguments[0].style.border='3px solid red'", passwordField);
passwordField.sendKeys ("Password123");
js.executeScript ("arguments[0].style.border='2px solid #ced4da'", passwordField);
WebElement loginBtn = driver.findElement (By.cssSelector ("input.btn"));
js.executeScript ("arguments[0].style.border='3px solid red'", loginBtn);
js.executeScript ("arguments[0].click();", loginBtn);
String titleText = js.executeScript ("return document.title;")
.toString ();
System.out.println ("Page Title is: " + titleText);
String domainName = js.executeScript ("return document.domain;")
.toString ();
System.out.println ("Domain is: " + domainName);
String myAccountHeader = driver.findElement (By.cssSelector ("#content h2"))
.getText ();
assertEquals (myAccountHeader, "My Account");
}
تنفيذ الاختبار
تظهر اللقطة الشاشية التالية من بيئة IntelliJ IDE أن الاختبار تم تنفيذه بنجاح.

سيناريو الاختبار 2
هدفنا هو كتابة كود بسيط لتوضيح مثال باستخدام طريقة executeAsyncScript()
باستخدام السيناريو الاختباري التالي.
- انتقل إلى موقع LambdaTest eCommerce Playground.
- انتقل لأسفل إلى أسفل الصفحة الرئيسية.
- قم بالتأكد من أن النص “FROM THE BLOG” معروض في الجزء السفلي من الصفحة.
التنفيذ:
أنشئ طريقة testExecuteAsyncScript()
جديدة في فئة النص الحالية TestJavaScriptExecutor
.
public void testExecuteAsyncScript() {
driver.get("https://ecommerce-playground.lambdatest.io");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeAsyncScript("var callback = arguments[arguments.length - 1];" + "window.scrollBy(0,document.body.scrollHeight); + callback()");
String fromTheBlogText = driver.findElement(By.cssSelector("#entry_217991 > h3")).getText();
assertEquals(fromTheBlogText, "FROM THE BLOG");
}
سيتم تصفح الكود إلى الصفحة الرئيسية لموقع لامبدا-تيست للتجارة الإلكترونية. سيتم استدعاء الطريقة executeAsyncScript()
من JavaScriptExecutor بعد ذلك، حيث ستقوم بتنفيذ الإجراء للتمرير في النافذة.
في طريقة executeAsyncScript()
، يجب أن توضح النصوص المُنفّذة أنها انتهت من خلال استدعاء الطريقة المُقدمة callback()
.
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeAsyncScript("var callback = arguments[arguments.length - 1];"
+ "window.scrollBy(0,document.body.scrollHeight); + callback()");
بعد التمرير إلى أسفل النافذة، سيتم تحديد نص “FROM THE BLOG”، وسيتم إجراء تأكيد عليه.
String fromTheBlogText = driver.findElement(By.cssSelector("#entry_217991 > h3")).getText();
assertEquals(fromTheBlogText, "FROM THE BLOG");
تنفيذ الاختبار
اللقطة الشاشة التالية تظهر أن الاختبار تم تنفيذه بنجاح.

أوامر لاستخدام JavaScriptExecutor في سيلينيوم
لنفحص بعض السيناريوهات التي يمكننا التعامل معها باستخدام واجهة JavaScriptExecutor لأتمتة اختبار سيلينيوم.
للنقر على زر:
js.executeScript("document.getElementById('enter element id').click();");
//or
js.executeScript("arguments[0].click();", okButton);
لكتابة نص في مربع نص دون استخدام الطريقة sendKeys()
:
js.executeScript("document.getElementById(id').value='someValue';");
js.executeScript("document.getElementById('Email').value='SeleniumTesting.com';");
للتعامل مع خانة الاختيار عن طريق تمرير القيمة كصحيحة أو خاطئة:
js.executeScript("document.getElementById('enter element id').checked=false;");
لإنشاء نافذة تنبيه بوب فيب في مشغل سيلينيوم:
js.executeScript("alert('Welcome To Selenium Testing');");
لتحديث نافذة المتصفح باستخدام JavaScript:
js.executeScript("history.go(0)");
للحصول على النص الداخلي لصفحة الويب بأكملها في سيلينيوم:
String innerText = js.executeScript(" return document.documentElement.innerText;").toString();
System.out.println(innerText);
للحصول على عنوان صفحة الويب:
String titleText = js.executeScript("return document.title;").toString();
System.out.println(titleText);
للحصول على اسم النطاق:
String domainName= js.executeScript("return document.domain;").toString();
System.out.println(domainName);
للحصول على عنوان URL لصفحة الويب:
String url= js.executeScript("return document.URL;").toString();
System.out.println(url);
للحصول على ارتفاع وعرض صفحة الويب:
js.executeScript(“return window.innerHeight;”).toString();
js.executeScript(“return window.innerWidth;”).toString();
للانتقال إلى صفحة مختلفة باستخدام JavaScript:
js.executeScript("window.location = 'https://www.google.com");
- للتمرير الصفحة عموديًا بمقدار 500 بكسل:
جافا
جافا.executeScript(“window.scrollBy(0,500)”);
- للتمرير عموديا حتى النهاية:
جافا
جافا.executeScript(“window.scrollBy(0,document.body.scrollHeight)”);
إضافة عنصر في نموذج الكائنات في الوثيقة (DOM):
js.executeScript("var btn=document.createElement('newButton');"
+ "document.body.appendChild(btn);");
للحصول على جذر الظل في DOM:
WebElement element = driver.findElement(By.id("shadowroot"));
js.executeScript("return arguments[0].shadowRoot", element);
الاستنتاج
لدى Selenium واجهة تسمى JavaScriptExecutor تُستخدم عندما لا تعمل أوامر WebDriver كما هو مقصود. بمساعدة JavaScriptExecutor، يمكننا استخدام WebDriver لتنفيذ رمز JavaScript على الموقع الإلكتروني، مما يسمح لنا بمعالجة مجموعة متنوعة من المهام بطريقة أنيقة وفعالة لا يمكن تحقيقها بالاعتماد فقط على Java.
في هذه المدونة، استكشفنا كيفية استخدام JavaScriptExecutor في Selenium وطرقه المختلفة. علاوة على ذلك، غطينا سيناريوهات مختلفة لتحقيق حلا فعالا باستخدام طرق مختلفة مع أمثلة عملية.
Source:
https://dzone.com/articles/how-to-use-javascriptexecutor-in-selenium