Вопрос-ответ

How to interact with the elements within #shadow-root (open) while Clearing Browsing Data of Chrome Browser using cssSelector

Как взаимодействовать с элементами в #shadow-root (открыто) при очистке данных просмотра браузера Chrome с помощью cssSelector

Я следил за обсуждением Как автоматизировать элементы shadow DOM с помощью selenium? для работы с #shadow-root (open) элементами.

В процессе поиска Clear data кнопки во всплывающем окне Очистить данные просмотра, которое появляется при доступе к URL-адресу chrome://settings/clearBrowserData через Selenium, я не могу найти следующий элемент:

#shadow-root (open)
<settings-privacy-page>

Моментальный снимок:

настройки-конфиденциальность-страница

Используя Selenium ниже приведены мои пробные версии кода и обнаруженные связанные с ними ошибки:


  • Попытка 1:


    WebElement root5 = shadow_root4.findElement(By.tagName("settings-privacy-page"));


    • Ошибка:


      Exception in thread "main" org.openqa.selenium.JavascriptException: javascript error: b.getElementsByTagName is not a function


  • Попытка 2:


    WebElement root5 = shadow_root4.findElement(By.cssSelector("settings-privacy-page"));


    • Ошибка:


      Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"settings-privacy-page"}


  • Попытка 3:


    WebElement root5 = (WebElement)((JavascriptExecutor)shadow_root4).executeScript("return document.getElementsByTagName('settings-privacy-page')[0]");


    • Ошибка:


      Exception in thread "main" java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to org.openqa.selenium.JavascriptExecutor


Если это полезно, начальный блок кода (до приведенной выше строки) работает идеально:

driver.get("chrome://settings/clearBrowserData");
WebElement root1 = driver.findElement(By.tagName("settings-ui"));
WebElement shadow_root1 = expand_shadow_element(root1);

WebElement root2 = shadow_root1.findElement(By.cssSelector("settings-main#main"));
WebElement shadow_root2 = expand_shadow_element(root2);

WebElement root3 = shadow_root2.findElement(By.cssSelector("settings-basic-page[role='main']"));
WebElement shadow_root3 = expand_shadow_element(root3);

WebElement root4 = shadow_root3.findElement(By.cssSelector("settings-section[page-title='Privacy and security']"));
WebElement shadow_root4 = expand_shadow_element(root4);

PS: expand_shadow_element() работает безупречно.

Переведено автоматически
Ответ 1

Если вы пытаетесь получить элемент "Очистить данные", вы можете использовать приведенный ниже js, чтобы получить элемент, а затем выполнить.

return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')

Вот пример скрипта.

driver.get("chrome://settings/clearBrowserData");
driver.manage().window().maximize();
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");
// now you can click on clear data button
clearData.click();

Правка 2: объяснение

Проблема: Selenium не предоставляет явной поддержки для работы с элементами Shadow DOM, поскольку их нет в текущем dom. Именно по этой причине мы получим NoSuchElementException исключение при попытке доступа к элементам в shadow dom.

Shadow DOM:
введите описание изображения здесь

Примечание: Мы будем ссылаться на термины, показанные на картинке. Поэтому, пожалуйста, просмотрите картинку для лучшего понимания.

Решение:

Для работы с shadow element сначала нам нужно найти shadow host, к которому прикреплен shadow dom. Вот простой метод получения shadow root на основе shadowHost.

private static WebElement getShadowRoot(WebDriver driver,WebElement shadowHost) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (WebElement) js.executeScript("return arguments[0].shadowRoot", shadowHost);
}

А затем вы можете получить доступ к элементу shadow tree с помощью элемента shadowRoot.

// get the shadowHost in the original dom using findElement
WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS"));
// get the shadow root
WebElement shadowRoot = getShadowRoot(driver,shadowHost);
// access shadow tree element
WebElement shadowTreeElement = shadowRoot.findElement(By.cssSelector("shadow_tree_element_css"));

Для упрощения всех вышеперечисленных шагов создан приведенный ниже метод.

public static WebElement getShadowElement(WebDriver driver,WebElement shadowHost, String cssOfShadowElement) {
WebElement shardowRoot = getShadowRoot(driver, shadowHost);
return shardowRoot.findElement(By.cssSelector(cssOfShadowElement));
}

Теперь вы можете получить элемент ShadowTree одним вызовом метода

WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS_Goes_here));
WebElement shadowTreeElement = getShadowElement(driver,shadowHost,"
shadow_tree_element_css");

И выполнять операции как обычно, например .click(), .getText().

shadowTreeElement.click()

Это выглядит просто, когда у вас есть только один уровень shadow DOM. Но здесь, в данном случае, у нас есть несколько уровней shadow doms. Таким образом, мы должны получить доступ к элементу, обращаясь к каждому теневому хосту и root.
введите описание изображения здесь

Ниже приведен фрагмент с использованием методов, упомянутых выше (getShadowElement и getShadowRoot).

// Locate shadowHost on the current dom
WebElement shadowHostL1 = driver.findElement(By.cssSelector("settings-ui"));

// now locate the shadowElement by traversing all shadow levels
WebElement shadowElementL1 = getShadowElement(driver, shadowHostL1, "settings-main");
WebElement shadowElementL2 = getShadowElement(driver, shadowElementL1,"settings-basic-page");
WebElement shadowElementL3 = getShadowElement(driver, shadowElementL2,"settings-section > settings-privacy-page");
WebElement shadowElementL4 = getShadowElement(driver, shadowElementL3,"settings-clear-browsing-data-dialog");
WebElement shadowElementL5 = getShadowElement(driver, shadowElementL4,"#clearBrowsingDataDialog");
WebElement clearData = shadowElementL5.findElement(By.cssSelector("#clearBrowsingDataConfirm"));
System.out.println(clearData.getText());
clearData.click();

Вы можете выполнить все вышеперечисленные шаги одним вызовом js, как указано в начале ответа (добавлено ниже просто для уменьшения путаницы).

WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");

Скриншот:
введите описание изображения здесь

Ответ 2

Мне пришлось выполнить аналогичный тест, который требовал очистки истории просмотра Chrome. Небольшое отличие заключалось в том, что я очищал данные после перехода в расширенный раздел всплывающего окна. Поскольку вы изо всех сил пытаетесь нажать только кнопку "Очистить данные", я совершенно уверен, что вы по ошибке пропустили один или два элемента иерархии. Или, возможно, перепутали дочерние и родительские элементы. Судя по вашему коду, я предполагаю, что вы уже знаете, что для доступа к определенному элементу shadow DOM вам нужна правильная последовательность, и это также было довольно подробно объяснено выше.
Переходя непосредственно к вашей проблеме, вот мой фрагмент кода, который работает правильно. Код ожидает, пока данные не будут очищены, а затем перейдет к следующему действию-

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

public void clearBrowsingHistory() throws Exception {

WebDriverWait wait = new WebDriverWait(driver, 15);
driver.get("chrome://settings/clearBrowserData");
// Get shadow root elements
WebElement shadowRoot1 = expandRootElement(driver.findElement(By.xpath("/html/body/settings-ui")));

WebElement root2 = shadowRoot1.findElement(By.cssSelector("settings-main"));
WebElement shadowRoot2 = expandRootElement(root2);

WebElement root3 = shadowRoot2.findElement(By.cssSelector("settings-basic-page"));
WebElement shadowRoot3 = expandRootElement(root3);

WebElement root4 = shadowRoot3
.findElement(By.cssSelector("#advancedPage > settings-section > settings-privacy-page"));
WebElement shadowRoot4 = expandRootElement(root4);

WebElement root5 = shadowRoot4.findElement(By.cssSelector("settings-clear-browsing-data-dialog"));
WebElement shadowRoot5 = expandRootElement(root5);

WebElement root6 = shadowRoot5
.findElement(By.cssSelector("cr-dialog div[slot ='button-container'] #clearBrowsingDataConfirm"));

root6.click();
wait.until(ExpectedConditions.invisibilityOf(root6));
}

В вашем случае это также должно работать должным образом, если вы не собираетесь изменять какие-либо параметры, выбранные по умолчанию во всплывающем окне (в этом случае вам придется добавить еще несколько кодов, касающихся установки этих флажков). Пожалуйста, скажите мне, решит ли это вашу проблему. Надеюсь, это полезно
Я также добавил снимок экрана сюда -
изображение

Ответ 3

Стратегия поиска в ответе @supputuri с использованием document.querySelector() идеально работает через

Однако, когда нужный элемент открывается из , вам нужно вызвать WebDriverWait для elementToBeClickable(), и вы можете предложить следующее решение:


  • Блок кода:


    driver.get("chrome://settings/clearBrowserData");
    new WebDriverWait(driver, 5).until(ExpectedConditions.elementToBeClickable((WebElement) ((JavascriptExecutor)driver).executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')"))).click();
    System.out.println("Clear data Button Clicked");


  • Вывод в консоль:


    Clear data Button Clicked


Ответ 4

Я получал InvalidArgumentException при попытке идентифицировать элемент shadowRoot в DOM с использованием Selenium 4.3.0 и Chrome версии 103.0.5060.134

Решение этой проблемы заключается в SearchContext se= driver.findElment(By.locator("...").getShadowRoot(); тип возвращаемого значения - SearchContext в строке выше попробуйте использовать locator как xpath и, во-вторых, попытайтесь найти элемент, используя ссылку SearchContext, например

WebElement we= se.findElement(By.locator("....."));
use locater as cssSelector

И бум, это работает как шарм

Я не нашел это решение доступным, и мне потребовалось полдня, чтобы разобраться, Надеюсь, это поможет!!!

java selenium