Как автоматизировать теневые элементы DOM с помощью селена?

Я использую проект Java Selenium для автоматизации веб-страниц. Веб-страница содержит множество многоуровневых элементов DOM с теневым корнем, с которыми я не могу взаимодействовать, используя метод селена findElement.

Я пробовал следующие решения:

  • deep css (не работает в последнем браузере Chrome)
  • JS-исполнитель. (Это действительно утомительно и становится сложным в обслуживании)

Примечание:

Если вам известно какое-либо другое решение, кроме перечисленных выше, которое я могу реализовать в среде Selenium Java, пожалуйста, передайте решение. Заранее спасибо !.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
16
0
40 585
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Чтобы продемонстрировать автоматизация из тень ДОМ с использованием Селен v3.x, ChromeDriver v2.46 и Chrome v73.x, вот несколько подходов, которые открывают URL-адрес chrome://downloads/ и с помощью метода executeScript() отправляет последовательность символовпдф как текст поиска в Поисковая строка.


Использование document.querySelector()

В качестве канонического подхода вы можете использовать метод document.querySelector() следующим образом:

  • Блок кода:

    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    public class shadow_DOM_search_download_querySelector {
    
        public static void main(String[] args)
        {
            System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
            ChromeOptions options = new ChromeOptions();
            options.addArguments("start-maximized");
            options.addArguments("disable-infobars");
            options.addArguments("--disable-extensions"); 
            WebDriver driver = new ChromeDriver(options);
            driver.get("chrome://downloads/");
            JavascriptExecutor jse = (JavascriptExecutor) driver; 
            WebElement search_box = (WebElement) jse.executeScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('downloads-toolbar#toolbar').shadowRoot.querySelector('cr-toolbar#toolbar').shadowRoot.querySelector('cr-toolbar-search-field#search').shadowRoot.querySelector('div#searchTerm input#searchInput')");
            String js = "arguments[0].setAttribute('value','pdf')";
            ((JavascriptExecutor) driver).executeScript(js, search_box);
        }
    }
    

Это же решение можно переписать пошагово следующим образом:

  • Блок кода:

    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    public class shadow_DOM {
    
        static WebDriver driver;
        public static void main(String[] args) 
        {   
            System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
            ChromeOptions options = new ChromeOptions();
            options.addArguments("start-maximized");
            //options.addArguments("disable-infobars");
            options.addArguments("--disable-extensions"); 
            driver = new ChromeDriver(options);
            driver.get("chrome://downloads/");
            WebElement root1 = driver.findElement(By.tagName("downloads-manager"));
            WebElement shadow_root1 = expand_shadow_element(root1);
    
            WebElement root2 = shadow_root1.findElement(By.cssSelector("downloads-toolbar#toolbar"));
            WebElement shadow_root2 = expand_shadow_element(root2);
    
            WebElement root3 = shadow_root2.findElement(By.cssSelector("cr-toolbar#toolbar"));
            WebElement shadow_root3 = expand_shadow_element(root3);
    
            WebElement root4 = shadow_root3.findElement(By.cssSelector("cr-toolbar-search-field#search"));
            WebElement shadow_root4 = expand_shadow_element(root4);
    
            WebElement search_term = shadow_root4.findElement(By.cssSelector("div#searchTerm input#searchInput"));
            String js = "arguments[0].setAttribute('value','pdf')";
            ((JavascriptExecutor) driver).executeScript(js, search_term);
    
            WebElement search_button = shadow_root4.findElement(By.cssSelector("paper-icon-button#icon"));
            search_button.click();
    
            System.out.println("Search Button Clicked");
        }
    
        public static WebElement expand_shadow_element(WebElement element)
        {
            WebElement shadow_root = (WebElement)((JavascriptExecutor)driver).executeScript("return arguments[0].shadowRoot", element);
            return shadow_root;
        }
    
    }
    

  • Выход консоли:

    Search Button Clicked
    

  • Снимок браузера:

shadowDOM


Outro

Согласно обсуждению в Определите судьбу экспериментального комбинатора '>>>', комбинатор >>>, который был заменой комбинатору /deep/ для прокалывания всех границ теневого DOM в стиле, который был реализован за флагом в Blink, устарел.

Ответ принят как подходящий

Есть очень хороший плагин, который можно использовать с селеновым проектом теневая автоматизация-селен. Это помогает писать намного лучший, читаемый и удобный код. Используя это, вы можете получить доступ к многоуровневому теневому DOM (до 4 уровней). Это использует простой селектор css для идентификации элементов.

WebElement findElement(String cssSelector): используйте этот метод, если вам нужен один элемент из DOM

List<WebElement> findElements(String cssSelector): используйте это, если хотите найти все элементы из DOM.

WebElement findElements(WebElement parent, String cssSelector): используйте это, если вы хотите найти отдельные элементы из родительского объекта DOM.

List<WebElement> findElements(WebElement parent, String cssSelector): используйте это, если вы хотите найти все элементы из родительского объекта DOM

WebElement getShadowElement(WebElement parent,String selector): используйте это, если вы хотите найти один элемент из родительского DOM.

List<WebElement> getAllShadowElement(WebElement parent,String selector): используйте это, если вы хотите найти все элементы из родительского DOM

boolean isVisible(WebElement element): используйте это, если вы хотите найти видимость элемента

boolean isChecked(WebElement element): используйте это, если вы хотите проверить, установлен ли флажок

boolean isDisabled(WebElement element): используйте это, если хотите проверить, отключен ли элемент

String getAttribute(WebElement element,String attribute): используйте это, если вы хотите получить такой атрибут, как aria-selected и другие пользовательские атрибуты элементов.

void selectCheckbox(String label): используйте это, чтобы выбрать элемент флажка с помощью метки.

void selectCheckbox(WebElement parentElement, String label): используйте это, чтобы выбрать элемент флажка с помощью метки.

void selectRadio(String label): используйте это, чтобы выбрать радиоэлемент с помощью метки.

void selectRadio(WebElement parentElement, String label): используйте это, чтобы выбрать радиоэлемент из родительского DOM с помощью метки.

void selectDropdown(String label): используйте это, чтобы выбрать элемент раскрывающегося списка с помощью метки (используйте это, если присутствует или загружен только один раскрывающийся список в пользовательском интерфейсе).

void selectDropdown(WebElement parentElement, String label): используйте это, чтобы выбрать элемент выпадающего списка из родительского DOM с помощью метки.

Как использовать этот плагин: Вам придется зависеть в вашем проекте.

Мавен

<dependency>
  <groupId>io.github.sukgu</groupId>
  <artifactId>automation</artifactId>
  <version>0.0.4</version>
<dependency>

для HTML-тега, который находится под теневым корневым элементом dom

<properties-page id = "settingsPage"> 
  <textarea id = "textarea">
</properties-page>

Вы можете использовать этот код в своем фреймворке, чтобы захватить объект элемента textarea.

  import io.github.sukgu.*;
  Shadow shadow = new Shadow(driver);
  WebElement element = shadow.findElement("properties-page#settingsPage>textarea#textarea");
  String text = element.getText();

Добро пожаловать в StackOverflow! Спасибо за ваш подробный ответ. Пожалуйста, поддержите его ссылками. У нас есть рекомендации по Как написать хороший ответ.

Joseph Cho 15.05.2019 15:39

Шаги, чтобы узнать теневые элементы DOM с помощью JSExecutor и CSS:

  1. Найдите базовый элемент, т.е. родительский элемент корневого элемента Shadow.

  2. Получить теневой корень этого элемента.

  3. И найди свой элемент на этом теневом корневом вебементе

    пример :

<div id = "example">
#shadow-root
<div id = "root" part = "root">
   <div id = "label" part = "label">ShadowRootLabel</div>
</div>
</ptcs-label>

#Метод определения теневого корневого элемента

public WebElement getShadowRootElement(WebElement element) {
WebElement ele = (WebElement) ((JavascriptExecutor)driver)
    .executeScript("return arguments[0].shadowRoot", element);
        return ele;
    }

# Шаг 1, например, найти базовый элемент:

WebElement root1 = driver.findElement(By.id("example"));

#Шаг 2

//Get shadow root element
WebElement shadowRoot1 = getShadowRootElement(root1);

#Шаг3 - Нам нужно найти элементы с помощью CSS Selector, которые находятся внутри теневого корня, xpath здесь не сработает

//Here we will get Element inside Shadow Dom Element
WebElement shadowElement = shadowRoot3.findElement(By.cssSelector("div[id=label]"));

Похоже, это больше не работает с Chrome 96+. При вызове driver.executeScript("return arguments[0].shadowRoot", element) возвращается карта com.google.common.collect.Maps$TransformedEntriesMap, которую нельзя преобразовать в WebElement. Любые идеи, как это исправить?

Jörg Rech 01.12.2021 23:08

Вам нужно выполнить приведение к SearchContext или использовать новый метод getShadowRoot(): titusfortner.com/2021/11/22/shadow-dom-selenium.html

titusfortner 13.12.2021 06:32

С Selenium 4 теперь есть WebElement.getShadowRoot(). Например:

driver.findElement(By.id("parentId")).getShadowRoot().findElement(By.cssSelector( "label" )).findElement(By.tagName("input"))

Как обычно с #shadow-root, выбор навигации для следующего прыжка ограничен. Например. против Chrome By.cssSelector() и By.className() действительны, но By.id() и By.tagName() не работают с org.openqa.selenium.InvalidArgumentException: invalid argument: invalid locator

Другие вопросы по теме