diff --git a/docs/demo/shadondom.html b/docs/demo/shadondom.html
new file mode 100644
index 0000000..ca4a6da
--- /dev/null
+++ b/docs/demo/shadondom.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+ This is styled by the main document
+
+
+
+
\ No newline at end of file
diff --git a/docs/demo/shadowdom.html b/docs/demo/shadowdom.html
new file mode 100644
index 0000000..3d89c57
--- /dev/null
+++ b/docs/demo/shadowdom.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+ Shadow Dom Test page
+ This is a div called shadow-box but not in Shadow Dom
+
+ Shadow Dom host 1:
+
+
+ Shadow Dom host 2:
+
+
+
+
+ We have also shadowdom in an iFrame
+
+
+
\ No newline at end of file
diff --git a/docs/demo/shadowdom2.html b/docs/demo/shadowdom2.html
new file mode 100644
index 0000000..28d66d4
--- /dev/null
+++ b/docs/demo/shadowdom2.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+ Shadow Dom in iFrame
+ This is a div in iFrame
+
+ Shadow Dom in Frame:
+
+
+ Shadow Dom in Frame 22:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/manifest.json b/docs/manifest.json
index b9b503f..98dc9b5 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -4781,6 +4781,26 @@
},
"version": ""
},
+ {
+ "type": "Resource",
+ "source_relative_path": "demo/shadowdom.html",
+ "output": {
+ "resource": {
+ "relative_path": "demo/shadowdom.html"
+ }
+ },
+ "version": ""
+ },
+ {
+ "type": "Resource",
+ "source_relative_path": "demo/shadowdom2.html",
+ "output": {
+ "resource": {
+ "relative_path": "demo/shadowdom2.html"
+ }
+ },
+ "version": ""
+ },
{
"type": "Resource",
"source_relative_path": "files/Data-HomeInsurance.xlsx",
diff --git a/src/AxaFrance.WebEngine.Doc/demo/shadowdom.html b/src/AxaFrance.WebEngine.Doc/demo/shadowdom.html
new file mode 100644
index 0000000..3d89c57
--- /dev/null
+++ b/src/AxaFrance.WebEngine.Doc/demo/shadowdom.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+ Shadow Dom Test page
+ This is a div called shadow-box but not in Shadow Dom
+
+ Shadow Dom host 1:
+
+
+ Shadow Dom host 2:
+
+
+
+
+ We have also shadowdom in an iFrame
+
+
+
\ No newline at end of file
diff --git a/src/AxaFrance.WebEngine.Doc/demo/shadowdom2.html b/src/AxaFrance.WebEngine.Doc/demo/shadowdom2.html
new file mode 100644
index 0000000..28d66d4
--- /dev/null
+++ b/src/AxaFrance.WebEngine.Doc/demo/shadowdom2.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+ Shadow Dom in iFrame
+ This is a div in iFrame
+
+ Shadow Dom in Frame:
+
+
+ Shadow Dom in Frame 22:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AxaFrance.WebEngine.Web/WebElementDescription.cs b/src/AxaFrance.WebEngine.Web/WebElementDescription.cs
index 8a29b2e..1d2ea1a 100644
--- a/src/AxaFrance.WebEngine.Web/WebElementDescription.cs
+++ b/src/AxaFrance.WebEngine.Web/WebElementDescription.cs
@@ -19,6 +19,8 @@ namespace AxaFrance.WebEngine.Web
///
public class WebElementDescription : ElementDescription
{
+ private bool isInFrame;
+
///
/// Initialize the Element. If the element is not created within a , you should use before us the element.
///
@@ -170,14 +172,32 @@ protected override IWebElement InternalFindElement()
protected override IReadOnlyCollection InternalFindElements()
{
IEnumerable elements = null;
- if (this.Id != null)
+ ISearchContext context = driver;
+ if (this.ShadowRoot != null)
+ {
+ ShadowRoot.UseDriver(driver);
+ var root = ShadowRoot.InternalFindElements();
+ if (root.Count > 1)
+ {
+ throw new InvalidSelectorException("Multiple element has found with the given selection criteria for ShadowRoot");
+ }
+ else if (root.Count == 0)
+ {
+ throw new NoSuchElementException("No such Shadow Root found:" + ShadowRoot.ToString());
+ }
+ else
+ {
+ context = root.First().GetShadowRoot();
+ }
+ }
+ if (this.Id != null)
{
- elements = driver.FindElements(By.Id(this.Id));
+ elements = context.FindElements(By.Id(this.Id));
}
if (this.Name != null)
{
- var names = driver.FindElements(By.Name(this.Name));
+ var names = context.FindElements(By.Name(this.Name));
if (elements == null)
{
elements = names;
@@ -191,7 +211,7 @@ protected override IReadOnlyCollection InternalFindElements()
if (this.ClassName != null)
{
string xpath = $"//*[@class='{ClassName}']";
- var cssnames = driver.FindElements(By.XPath(xpath));
+ var cssnames = context.FindElements(By.XPath(xpath));
if (elements == null)
{
elements = cssnames;
@@ -204,7 +224,7 @@ protected override IReadOnlyCollection InternalFindElements()
if (this.LinkText != null)
{
- var links = driver.FindElements(By.LinkText(this.LinkText));
+ var links = context.FindElements(By.LinkText(this.LinkText));
if (elements == null)
{
elements = links;
@@ -217,7 +237,7 @@ protected override IReadOnlyCollection InternalFindElements()
if (this.TagName != null)
{
- var tagNames = driver.FindElements(By.TagName(TagName.ToUpper()));
+ var tagNames = context.FindElements(By.TagName(TagName.ToUpper()));
if (elements == null)
{
elements = tagNames;
@@ -230,7 +250,7 @@ protected override IReadOnlyCollection InternalFindElements()
if (this.CssSelector != null)
{
- var classes = driver.FindElements(By.CssSelector(CssSelector));
+ var classes = context.FindElements(By.CssSelector(CssSelector));
if (elements == null)
{
elements = classes;
@@ -244,7 +264,7 @@ protected override IReadOnlyCollection InternalFindElements()
if (this.XPath != null)
{
- var xpaths = driver.FindElements(By.XPath(this.XPath));
+ var xpaths = context.FindElements(By.XPath(this.XPath));
if (elements == null)
{
elements = xpaths;
@@ -263,7 +283,7 @@ protected override IReadOnlyCollection InternalFindElements()
}
else
{
- elements = driver.FindElements(By.XPath($"//*[text()='{InnerText}']"));
+ elements = context.FindElements(By.XPath($"//*[text()='{InnerText}']"));
}
}
@@ -275,7 +295,7 @@ protected override IReadOnlyCollection InternalFindElements()
attributes.Add($"[{a.Name}=\"{a.Value}\"]");
}
string cssSelector = $"{string.Join("", attributes)}";
- var attr = driver.FindElements(By.CssSelector(cssSelector));
+ var attr = context.FindElements(By.CssSelector(cssSelector));
if (elements == null)
{
elements = attr;
@@ -293,7 +313,6 @@ protected override IReadOnlyCollection InternalFindElements()
else
{
return new ReadOnlyCollection(elements.ToList());
-
}
}
@@ -367,6 +386,15 @@ public bool IsVisibleInViewPort
}
}
+ ///
+ /// Describes the ShadowRoot if the element is placed in a shadow DOM.
+ /// The description of the current element wil be based in the scope of the ShadowRoot.
+ ///
+ ///
+ /// Warning: When searching an element in the ShadowRoot: You can only use CssSelctor to describe the element.
+ ///
+ public WebElementDescription ShadowRoot { get; set; }
+
private bool InternalInViewPort()
{
//https://stackoverflow.com/questions/45243992/verification-of-element-in-viewport-in-selenium/45244889#45244889
diff --git a/src/WebEngine.Test/UnitTests/FramesShadowDoms.cs b/src/WebEngine.Test/UnitTests/FramesShadowDoms.cs
new file mode 100644
index 0000000..053a2e1
--- /dev/null
+++ b/src/WebEngine.Test/UnitTests/FramesShadowDoms.cs
@@ -0,0 +1,128 @@
+using AxaFrance.WebEngine;
+using AxaFrance.WebEngine.Web;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using OpenQA.Selenium;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebEngine.Test.UnitTests
+{
+ [TestClass]
+ public class FramesShadowDoms
+ {
+ static WebDriver driver = null;
+
+ [ClassCleanup]
+ public static void Cleanup()
+ {
+ try
+ {
+ driver?.Quit();
+ }
+ catch { }
+ try
+ {
+ driver?.Close();
+ }
+ catch { }
+ try
+ {
+ driver?.Dispose();
+ }
+ catch { }
+ }
+
+ [ClassInitialize]
+ public static void Initialize(TestContext context)
+ {
+ if (driver == null)
+ {
+ driver = BrowserFactory.GetDriver(AxaFrance.WebEngine.Platform.Windows, BrowserType.ChromiumEdge);
+ }
+
+ driver.Navigate().GoToUrl("https://axafrance.github.io/webengine-dotnet/demo/shadowdom.html");
+ }
+
+ [TestMethod]
+ public void ShadowDom()
+ {
+ WebElementDescription wed = new WebElementDescription(driver)
+ {
+ CssSelector = ".shadow-box",
+ ShadowRoot = new WebElementDescription()
+ {
+ Id = "host"
+ }
+ };
+ var element = wed.FindElement();
+ var text = element.GetDomProperty("innerText");
+ Assert.AreEqual("Hello, Shadow DOM!", text);
+ }
+
+ [TestMethod]
+ public void MultipleShadowDom()
+ {
+ WebElementDescription wed = new WebElementDescription(driver)
+ {
+ CssSelector = ".shadow-box",
+ ShadowRoot = new WebElementDescription()
+ {
+ Id = "host2"
+ }
+ };
+ var element = wed.FindElement();
+ var text = element.GetDomProperty("innerText");
+ Assert.AreEqual("Hello, Shadow DOM in the second div!", text);
+ }
+
+ [TestMethod]
+ public void NestedShadowDom()
+ {
+ WebElementDescription wed = new WebElementDescription(driver)
+ {
+ CssSelector = ".shadow-box",
+ ShadowRoot = new WebElementDescription()
+ {
+ Id = "host3",
+ ShadowRoot = new WebElementDescription()
+ {
+ Id = "host2",
+ }
+ }
+ };
+ var element = wed.FindElement();
+ var text = element.GetDomProperty("innerText");
+ Assert.AreEqual("Hello, Shadow DOM in a Shadow DOM!", text);
+ }
+
+ [TestMethod]
+ public void ShadowDomInFrame()
+ {
+ var Frame = new WebElementDescription(driver)
+ {
+ Id = "Frame1"
+ };
+
+ WebElementDescription wed = new WebElementDescription(driver)
+ {
+ CssSelector = ".shadow-box",
+ ShadowRoot = new WebElementDescription()
+ {
+ Id = "host"
+ }
+ };
+
+ //goto Frame1
+ driver.SwitchTo().Frame(Frame.FindElement());
+ var element = wed.FindElement();
+ var text = element.GetDomProperty("innerText");
+ driver.SwitchTo().DefaultContent();
+ Assert.AreEqual("Hello, Shadow DOM in Frame!", text);
+
+
+ }
+ }
+}
diff --git a/src/WebEngine.Test/UnitTests/WebTest.cs b/src/WebEngine.Test/UnitTests/WebTest.cs
index 7a42afc..a85c21b 100644
--- a/src/WebEngine.Test/UnitTests/WebTest.cs
+++ b/src/WebEngine.Test/UnitTests/WebTest.cs
@@ -46,6 +46,7 @@ public static void Initialize(TestContext context)
driver.Navigate().GoToUrl("https://axafrance.github.io/webengine-dotnet/demo/Test.html");
}
+
[TestMethod]
public void ElementTypeing()
{