Визуальное представление: https://www.youtube.com/watch?v=xAwoHvdLZXk

Предположим, что, будучи Front-end разработчиком, мы реализуем конкретное расширение, которое требует взаимодействия со многими другими сайтами клиента. И это расширение вызывает конфликты CSS при рендеринге на клиентских сайтах. Теперь возникает вопрос, как поступить с этой проблемой? Разработчики применили определенное решение {обсуждается ниже}, чтобы избавиться от своей проблемы, но теперь новая проблема была передана специалистам по автоматизации QA.

Только в контексте вышеупомянутой проблемы, переданной ребятам из отдела автоматизации контроля качества:будучи инженером по автоматизации контроля качества, когда вы пытаетесь найти веб-элементы, используя все стратегии локатора Selenium, и у вас ничего не получается. Каковы будут ваши чувства в этот момент, особенно когда вас окружают младшие? С правильным x-path, который мы обычно применяем при ежедневной реализации скриптов, каждый раз, когда вы получаете пустое или NULL на консоли инструментов веб-разработчика. И, очевидно, «NoSuchElementException» при попытке выполнить тот же x-путь со скриптом Selenium. Ну и что дальше……. ????

Первая проблема с решением

Проведя несколько часов в Google, мы обнаружили, что веб-приложение отображает отдельный Shadow DOM, и мы пытались взаимодействовать с этими элементами Shadow DOM, используя устаревшие стратегии поиска Selenium. Прежде чем перейти ко второй проблеме, давайте разберемся, что такое Shadow DOM?

На приведенном выше рисунке мы можем понять, что Shadow DOM позволяет прикреплять скрытые деревья Shadow DOM к элементам в основном дереве DOM — это дерево теневой DOM начинается с отдельного корня тени, под которым можно прикрепить любые элементы, которые вы хотите, в так же, как основной DOM. Мы можем рассмотреть следующую терминологию:

Теневой хост:основной узел DOM, который подключается к теневой DOM.

Теневой корень:входной узел теневого дерева DOM.

Граница теней:LoC, где заканчивается теневой DOM и начинается основной DOM

Теневое дерево:дерево DOM внутри теневого DOM

Теперь возникает следующий вопрос: Почему разработчики используют Shadow DOM? Shadow DOM — это своего рода веб-стандарт, который разработчики используют для инкапсуляции своего пользовательского HTML-кода и компонентов стиля, чтобы никакие другие глобальные компоненты стиля не могли переопределить их код. Это гарантирует, что компонент будет работать в любой среде, даже если на странице запущен другой CSS или JavaScript, то есть Shadow DOM скрывает сложность компонентов от остальной части страницы, поскольку он отображается отдельно от основного DOM. Теневой DOM всегда изолирован от основного DOM, на который всегда не влияют никакие изменения, внесенные в основные элементы DOM. Возьмем один распространенный пример: плагин для браузера, который может подключаться к любому типу браузера и отображать свой собственный HTML-код параллельно с основным HTML-кодом DOM, не затрагивая основные HTML-элементы DOM, а также не подвергаясь влиянию основного DOM. глобальные свойства стиля.

С одной стороны, хотя теневая DOM и является благом для веб-разработчиков интерфейса, она становится проклятием для автоматизации контроля качества, поскольку эти пользовательские HTML-элементы внутри теневого корня логически не существуют в основной DOM документа.

Вторая проблема с решением

С настройками браузера по умолчанию мы не можем видеть записи shadowRoot в консоли инструментов веб-разработчика, так что нам теперь делать? Давайте включим свойство Elements 'Show User Agent Shadow DOM' в настройках консоли браузера:

После включения этого свойства мы можем видеть элементы дерева Shadow DOM с тегом shadowRoot. Устаревшие селекторы Selenium по-прежнему не могут взаимодействовать с этими пользовательскими элементами в теневой модели DOM. Что дальше?

Selenium — это повар с ограниченным количеством рецептов, т. е. имеет устаревшие селекторы с ограниченной мощностью, что не позволяет ему взаимодействовать с пользовательскими HTML-элементами Shadow DOM, и мы получаем следующий ответ, т. е. Пустой или NULL на консоли. {На снимке экрана ниже: выделено красным — элемент не найден}

Valid XPATH -> $x('//*[text()[contains(.,"Name of Element")]]')

Valid JAVASCRIPT -> document.querySelector('html-tag').shadowRoot.querySelector('html-tag').shadowRoot.querySelector('html-tag#ID div html-tag').shadowRoot.querySelector('html-tag html-tag')

{На снимке экрана выше: выделен синим цветом — элемент успешно отображается в консоли}

Нам очень хорошо известно, что JavaScript намного мощнее, поскольку он получает полный доступ к DOM {Main DOM, а также Shadow DOM}. Итак, давайте продвинем Selenium от повара до шеф-повара, потому что шеф-повар всегда остается со своими рецептами, а также изобретает новые, когда это требуется в ситуации. В нашем случае мы можем изобрести новый рецепт, смешав JavaScript в правильных пропорциях с Selenium WebDriver. На приведенном выше рисунке мы видим, что необходимые элементы, найденные с помощью javascript, то есть интерфейс документа, сначала входят в основной DOM, а затем взаимодействуют с интерфейсом shadowRoot только для входа в дерево теневого DOM.

Теперь Selenium продвигается как шеф-повар и готов обслуживать новый рецепт, то есть готов выполнять действия с пользовательскими веб-элементами Shadow DOM. Для этого он должен носить новую шапку интерфейса JavascriptExecutor.

JavascriptExecutor jsExecutor = (JavascriptExecutor) new ChromeDriver();

Наконец, JavascriptExecutor будет выполнять действия над «простыми элементами javascript», а также «javascript с элементами интерфейса shadowRoot» с помощью метода executeScript {ниже фрагмента кода, написанного на Java}.

// Возвращаем веб-элемент после выполнения функции executeScript() для основных элементов DOM

WebElement userName = (WebElement) jsExecutor.executeScript("return document.querySelector('div.container input#username')"); WebElement userPassword = (WebElement) jsExecutor.executeScript("return document.querySelector('div.container input#password')"); WebElement loginButton = (WebElement) jsExecutor.executeScript("return document.querySelector('div.container input.login_button')");

// Selenium WeDriver выполняет действия над основными элементами DOM, чтобы получить логин

String js = "arguments[0].setAttribute('value', 'UserNamePassword')"; jsExecutor.executeScript(js, userName); jsExecutor.executeScript(js, userPassword); loginButton.click();

// #Возвращаем веб-элемент после выполнения функции executeScript() для элементов Shadow DOM

WebElement sampleShadowDomElement = (WebElement) jsExecutor.executeScript("return document.querySelector('SHADOW_DOM_ELEMENT').shadowRoot.querySelector('SHADOW_DOM_ELEMENT').shadowRoot.querySelector('.className #idName')");

// Selenium WeDriver нажимает на элемент Shadow DOM

sampleShadowDomElement.click();

Несколько исключений

Элементы Shadow DOM имеют два разных режима, т.е.

«Открытый режим»shadowRoot доступен и элементы видны на консоли.

«Закрытый режим»shadowRoot всегда имеет значение null и элементы не отображаются в консоли.

Blender Selenium WebDriver и JavaScript может выполнять действия только с элементами Shadow DOM в открытом режиме. Элементы Shadow DOM поддерживаются только следующими браузерами: Chrome v57+, Firefox v63+, Edge на основе Chromium v75+.

Вывод

# Подход, который мы обсуждали выше, полезен, если у вас есть какая-либо существующая платформа Selenium [с любой технологией, например, Java/Python и т. д.], и ваше веб-приложение использует Shadow DOM на нескольких веб-страницах.

# Если ваше веб-приложение полностью использует Shadow DOM, но вам нужно запустить свою среду автоматизации, я бы посоветовал использовать инструмент WebdriverIO версии 5.5.0, который неявно поддерживает элементы Shadow DOM {подробнее см. , посмотрите ссылки}.

Надеемся, что в будущем Selenium обеспечит полную поддержку пользовательских элементов Shadow DOM.

использованная литература

Понимание Shadow DOM:
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM

Действия с теневыми элементами DOM с помощью WebdriverIO:https://webdriver.io/blog/2019/02/22/shadow-dom-support.html

PolymerJS от Google визуализирует Shadow DOM:
https://polymer-library.polymer-project.org/2.0/docs/devguide/shadow-dom

Первоначально опубликовано на https://www.linkedin.com