Leveraging Selenium for testing Polymer components and shadow DOM structures

Having trouble using Selenium with elements inside a shadow DOM. Is there a specific method to handle this situation? Any guidance on what I might be doing wrong?

Here are the various approaches I've attempted:

var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().forBrowser('chrome').build();

driver.get('https://shop.polymer-project.org/');

// Trying to locate shop-app #shadow-root app-header
//

// Works fine without shadow DOMs
driver.findElement(webdriver.By.css('shop-app'));

// Fails due to:
// NoSuchElementError: no such element: Unable to locate element
driver.findElement(webdriver.By.css('shop-app /deep/ app-header'));

// Fails due to:
// NoSuchElementError: no such element: Unable to locate element
driver.findElement(webdriver.By.css('shop-app::shadow app-header'));

// Fails due to:
// TypeError: Custom locator did not return a WebElement
driver.findElement(webdriver.By.js(function() {
    return document.querySelector('shop-app /deep/ app-header');
}));

// Fails due to:
// TypeError: Custom locator did not return a WebElement
driver.findElement(webdriver.By.js(function() {
    return document.querySelector('shop-app::shadow app-header');
}));

// Fails due to:
// WebDriverError: unknown error: Cannot read property 'querySelector' of null
driver.findElement(webdriver.By.js(function() {
    return document.querySelector('shop-app').shadowRoot.querySelector('app-header');
}));

// Fails due to:
// WebDriverError: unknown error: Cannot read property 'header' of undefined
driver.findElement(webdriver.By.js(function() {
    return document.querySelector('shop-app').$.header;
}));

Using node 7.1.0 and selenium-webdriver 3.0.1.

Answer №1

In my opinion, it is more effective to utilize selenium selectors and inject the script specifically to access the shadow root:

def expand_shadow_element(element):
  shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
  return shadow_root

outer = expand_shadow_element(driver.find_element_by_css_selector("#test_button"))
inner = outer.find_element_by_id("inner_button")
inner.click()

To illustrate this, I have provided a practical example with Chrome's download page. Clicking the search button requires accessing 3 nested shadow root elements: https://i.sstatic.net/jRtdz.png

import selenium
from selenium import webdriver
driver = webdriver.Chrome()


def expand_shadow_element(element):
  shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
  return shadow_root

driver.get("chrome://downloads")
root1 = driver.find_element_by_tag_name('downloads-manager')
shadow_root1 = expand_shadow_element(root1)

root2 = shadow_root1.find_element_by_css_selector('downloads-toolbar')
shadow_root2 = expand_shadow_element(root2)

root3 = shadow_root2.find_element_by_css_selector('cr-search-field')
shadow_root3 = expand_shadow_element(root3)

search_button = shadow_root3.find_element_by_css_selector("#search-button")
search_button.click()

Using the same method as described in the previous answers has its limitations as it involves hard-coding the queries, decreases readability, and restricts the use of intermediary selections for other actions:

search_button = driver.execute_script('return document.querySelector("downloads-manager").shadowRoot.querySelector("downloads-toolbar").shadowRoot.querySelector("cr-search-field").shadowRoot.querySelector("#search-button")')
search_button.click()

Answer №2

To interact with the Shadow DOM, utilize the driver.executeScript() method.

Next, employ "client" Javascript to navigate through the Shadow DOM layers.

For a detailed example, refer to this response on Stack Overflow.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to use Javascript to gradually fade in text, one word at a time, with multiple divs instead of just one?

I am attempting to gradually fade in individual words from a div. While the code below works fine for a single div, it does not execute sequentially when multiple divs are involved. Here is the fiddle : http://jsfiddle.net/zlud/6czap/110/ Can anyone spot ...

Troubleshooting an issue with importing a Component in ReactJS using material-ui

Using the material-ui library, I attempted to create a Table following the code provided in the Custom Table Pagination Action example. However, I encountered the following error: Error Encountered: Warning: React.createElement: type is invalid -- expect ...

Utilize context.isPointInPath(x, y) in HTML5 Canvas for intricate shapes that contain multiple paths

I am currently working on a project that involves drawing a complex shape composed of 6 thin lines and two thick lines. In my code, I have defined 8 paths to achieve this: context.save(); context.lineWidth=2; var TAB_ABSTAND=10; var T ...

Shifting a div from side to side

I don't have much experience with coding, so I was hoping for some assistance. My goal was to create a div that moves back and forth using toggleClass; $('div').on('click', function() { $(this).toggleClass('active') ...

tips for handling socket.timeout error in selenium with python

When using selenium 2.44 and Firefox 34.0, I have encountered a problem on a website where the page loads inconsistently, sometimes resulting in a socket.timeout error (indicated by the spinning Firefox loading icon). After this error occurs, any attempts ...

JavaScript function to add or remove a class upon clicking

Currently experiencing an issue with my accordion functionality. I have successfully implemented code that allows for toggling one heading open at a time, but I am struggling to add an open/close image beside each heading. At the moment, when a heading is ...

Revise if a specific file is not being called by AJAX

I am currently utilizing a routing library known as Grapnel.js. It requires URLs in the format of index.php#something/something, which is why I am using htaccess to rewrite /something/something to match that structure. However, I would like the flexibility ...

Creating a data visualization in JavaScript or jQuery without relying on pre-built graph libraries

Hey there, I could really use some assistance. Does anyone know if it's possible to create a line graph in JavaScript or jQuery without relying on any external libraries? It doesn't have to be visually stunning, just functional. If you have any i ...

Employ the faker.js library to automatically create a form within casperjs environment

When using Casperjs to fill and submit forms, it is necessary to manually input the data each time. On the other hand, Faker.js can generate fake data that can be used in forms. The question then arises - how can these two be combined effectively? Consider ...

Tips for extracting only a portion of the JavaScript timestamp

I have a JavaScript timestamp that reads Tue Sep 30 2014 12:02:50 GMT-0400 (EDT). When I use the .getTime() method, I get 1412092970.768 Typically, this timestamp represents a specific time of today. My question is whether it's possible to extract o ...

Troubleshooting issues with AngularJS's minDate functionality

I have been trying to set the minDate for the datepicker to today, following the example on the angularJS bootstrap site. However, it seems like something is not working correctly. There are no console errors showing up, but it appears that the minDate is ...

What is the most effective way to display a card with varying values depending on the user's input in a form?

For a while now, I've been grappling with a particular challenge. In my project, I am utilizing multiple states to display values within a card after they are entered into a form. The first state captures the values and modifies the initial state, whi ...

Tips for preloading cookies prior to the initial request using Python3 and the Selenium Chrome WebDriver

Can cookies be added to a domain, such as stackoverflow.com, in Selenium Chrome WebDriver before making a request to a page on the same domain using get()? When attempting to do so: driver.webdriver.add_cookie({'name' : 'testcookie', & ...

The issue with mapDispathToProps is that it is failing to assign a function

import React, { Component } from "react"; import PropTypes from "prop-types"; import { connect } from "react-redux"; import { ShelfModal } from "./shelf-modal"; import { openShelfModal } from "../../../redux/actions/shelf-modal"; export class ShelfTest ex ...

VueJS: interactive input field with dynamic value binding using v-model

I am facing an issue with VueJS regarding setting the value of an input radio along with v-model. I am confused as to why I am unable to dynamically set a value to an input and use a model to retrieve the user's selection. Here is a clearer represent ...

Running a local project with the help of the Express framework

// Setting up the configuration for serving files from the source directory var express = require('express'); // Importing express module var path = require('path'); // Importing path module var open = require('open'); // Imp ...

Expanding size on hover without affecting the alignment of surrounding elements

Imagine there are 10 divs on the page styled as squares, collectively known as the home page. Among these 10: 3 divs belong to the .event1 class, 5 divs belong to the .event2 class, and 2 divs belong to the .event3 class. <div class="boxes event1"> ...

Leveraging API JSON information in conditional return statements with React

Working on a small Express/React app (not for production), I am validating a hashed pin in express and returning either message: false if validation fails or message: <cardnumber> if validation is successful. Currently, in my react frontend, I am try ...

Issues with implementing Callouts CSS in Highcharts are causing complications

Currently, I am attempting to construct a callout, and I aim to format the callouts using CSS. Unfortunately, the CSS implementation seems to be malfunctioning for some unknown reason. Below is the HTML: <script src="https://code.highcharts.com/highch ...

Using React to redirect a category of components to a specific sub-path, such as transforming "/templates" to "/templates/list"

Having a React app, I'm looking for a way to avoid duplicating the function of redirecting users to /<component>/list in every component if they visit just /<component>. How can this be achieved at a higher level? I have a layout componen ...