From 64d6ade45f324245cb38b79b0cf135c388199c3c Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 25 Feb 2025 10:33:12 -0500 Subject: [PATCH] [dotnet] Enable ShadowRoot to use `By` query mechanism --- dotnet/src/webdriver/ShadowRoot.cs | 32 +++++++++++++++++--- dotnet/test/common/ShadowRootHandlingTest.cs | 16 ++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/dotnet/src/webdriver/ShadowRoot.cs b/dotnet/src/webdriver/ShadowRoot.cs index a872d4fbc7d74..eac61b17147bc 100644 --- a/dotnet/src/webdriver/ShadowRoot.cs +++ b/dotnet/src/webdriver/ShadowRoot.cs @@ -30,7 +30,7 @@ namespace OpenQA.Selenium /// /// Provides a representation of an element's shadow root. /// - public class ShadowRoot : ISearchContext, IWrapsDriver, IWebDriverObjectReference + public class ShadowRoot : ISearchContext, IWrapsDriver, IWebDriverObjectReference, IFindsElement { /// /// The property name that represents an element shadow root in the wire protocol. @@ -93,10 +93,21 @@ public IWebElement FindElement(By by) throw new ArgumentNullException(nameof(by), "by cannot be null"); } + return by.FindElement(this); + } + + /// + /// Finds a child element matching the given mechanism and value. + /// + /// The mechanism by which to find the element. + /// The value to use to search for the element. + /// The first matching the given criteria. + public virtual IWebElement FindElement(string mechanism, string value) + { Dictionary parameters = new Dictionary(); parameters.Add("id", this.shadowRootId); - parameters.Add("using", by.Mechanism); - parameters.Add("value", by.Criteria); + parameters.Add("using", mechanism); + parameters.Add("value", value); Response commandResponse = this.driver.InternalExecute(DriverCommand.FindShadowChildElement, parameters); return this.driver.GetElementFromResponse(commandResponse); @@ -117,10 +128,21 @@ public ReadOnlyCollection FindElements(By by) throw new ArgumentNullException(nameof(by), "by cannot be null"); } + return by.FindElements(this); + } + + /// + /// Finds all child elements matching the given mechanism and value. + /// + /// The mechanism by which to find the elements. + /// The value to use to search for the elements. + /// A collection of all of the IWebElements matching the given criteria. + public virtual ReadOnlyCollection FindElements(string mechanism, string value) + { Dictionary parameters = new Dictionary(); parameters.Add("id", this.shadowRootId); - parameters.Add("using", by.Mechanism); - parameters.Add("value", by.Criteria); + parameters.Add("using", mechanism); + parameters.Add("value", value); Response commandResponse = this.driver.InternalExecute(DriverCommand.FindShadowChildElements, parameters); return this.driver.GetElementsFromResponse(commandResponse); diff --git a/dotnet/test/common/ShadowRootHandlingTest.cs b/dotnet/test/common/ShadowRootHandlingTest.cs index 7fa25654dd10f..561118db89ca8 100644 --- a/dotnet/test/common/ShadowRootHandlingTest.cs +++ b/dotnet/test/common/ShadowRootHandlingTest.cs @@ -18,6 +18,7 @@ // using NUnit.Framework; +using System.Collections.ObjectModel; namespace OpenQA.Selenium { @@ -42,8 +43,23 @@ public void ShouldFindElementUnderShadowRoot() driver.Url = shadowRootPage; IWebElement element = driver.FindElement(By.CssSelector("custom-checkbox-element")); ISearchContext shadowRoot = element.GetShadowRoot(); + IWebElement elementInShadow = shadowRoot.FindElement(By.CssSelector("input")); Assert.That(elementInShadow.GetAttribute("type"), Is.EqualTo("checkbox"), "Did not find element in shadow root"); + + ReadOnlyCollection elementsInShadow = shadowRoot.FindElements(By.CssSelector("input")); + Assert.That(elementsInShadow, Has.One.Items, "Did not find element in shadow root"); + Assert.That(elementsInShadow[0].GetAttribute("type"), Is.EqualTo("checkbox"), "Did not find element in shadow root"); + } + + [Test] + [IgnoreBrowser(Browser.Firefox, "Firefox does not support finding Shadow DOM elements")] + public void ShouldUseByMethodsToFindElementsUnderShadowRoot() + { + driver.Url = shadowRootPage; + IWebElement element = driver.FindElement(By.CssSelector("custom-checkbox-element")); + ISearchContext shadowRoot = element.GetShadowRoot(); + Assert.That(shadowRoot.FindElements(By.Id("")), Is.Empty, "Searching for elements by empty ID should return empty"); } [Test]