diff --git a/Vaft.Framework/DriverFactory/LocalDriverFactory.cs b/Vaft.Framework/DriverFactory/LocalDriverFactory.cs
index f4aa2fc..f342fa0 100644
--- a/Vaft.Framework/DriverFactory/LocalDriverFactory.cs
+++ b/Vaft.Framework/DriverFactory/LocalDriverFactory.cs
@@ -70,6 +70,8 @@ private IWebDriver CreateFirefoxDriver()
var ffp = new FirefoxProfile();
ffp.SetPreference("intl.accept_languages", Config.Settings.RuntimeSettings.BrowserLanguage);
+ ffp.SetPreference("dom.webcomponents.enabled",true);
+ ffp.SetPreference("dom.webcomponents.shadowdom.enabled",true);
var proxy = GetProxy();
if (proxy != null)
{
diff --git a/Vaft.Framework/Element/Customization/WebComponents/WebComponentsElement.cs b/Vaft.Framework/Element/Customization/WebComponents/WebComponentsElement.cs
new file mode 100644
index 0000000..d68bfdd
--- /dev/null
+++ b/Vaft.Framework/Element/Customization/WebComponents/WebComponentsElement.cs
@@ -0,0 +1,460 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using OpenQA.Selenium;
+using OpenQA.Selenium.Chrome;
+using OpenQA.Selenium.Edge;
+using OpenQA.Selenium.Firefox;
+using OpenQA.Selenium.IE;
+using OpenQA.Selenium.Internal;
+using OpenQA.Selenium.Opera;
+using OpenQA.Selenium.Remote;
+using OpenQA.Selenium.Support.PageObjects;
+
+namespace Vaft.Framework.Element.Customization.WebComponents
+{
+ public class WebComponentsElement : IWebElement, IWrapsElement
+ {
+ private const string JavaScriptHelperFilePath = "Vaft.Framework.Element.Customization.WebComponents.WebComponentsElementHelper.js";
+ private readonly By _by;
+ private readonly IWebDriver _webdriver;
+ private IWebElement _cashedElement;
+ private IWebElement _parrentField;
+ private readonly List _parrentFieldSelectors;
+ private List _parrentFields;
+
+
+ /// ShadowDomWebElement constructor
+ ///
+ /// WebDriver object
+ /// Element selector
+ /// List of parent element selectors. This param can be used if there is a need explicitly define parent selector or selectors that are outside target element shadow dom.
+ ///
+ public WebComponentsElement(IWebDriver driver, By by, List parrentSelectors = null)
+ {
+ _webdriver = driver;
+ _by = by;
+ _parrentFieldSelectors = parrentSelectors;
+ }
+
+
+ /// Static ShadowDomWebElement initializator
+ /// WebDriver object
+ /// Element selector
+ /// List of parent element selectors. This param can be used if there is a need explicitly define parent selector or selectors that are outside target element shadow dom.
+ public static WebComponentsElement CreateInstance(IWebDriver driver, By by, List parentSelectors = null)
+ {
+ return new WebComponentsElement(driver, by, parentSelectors);
+ }
+
+ public IWebElement Element
+ {
+ get
+ {
+ IWebElement parentField = _parrentField;
+ if (_parrentFieldSelectors != null && _parrentFieldSelectors.Any())
+ {
+ _parrentFields = FindParrentFields();
+ if (_parrentFields != null && _parrentFields.Any())
+ {
+ parentField = _parrentFields.Last();
+ }
+ }
+
+ How how = GetFindMethod(_by);
+ string usingstring = GetUsingString(how, _by);
+ _cashedElement = SearchElement(how, usingstring, parentField);
+ return _cashedElement;
+ }
+ }
+
+ ///
+ /// Search for IwebElement by given By selector. Element search is done at first in the main page DOM and if no elements were found then element search is done in all existing Shadow DOM's
+ ///
+ ///
+ ///
+ public IWebElement FindElement(By by)
+ {
+ IWebElement expectedElement = null;
+
+ //1st seach in current element shadow root
+ How howMethod = GetFindMethod(by);
+ string usingString = GetUsingString(howMethod, by);
+ try
+ {
+ expectedElement = SearchElement(howMethod, usingString, Element);
+ if (expectedElement != null)
+ {
+ return expectedElement;
+ }
+ }
+ catch (Exception)
+ {
+ // ignored
+ }
+
+ //2nd search in current element
+ try
+ {
+ expectedElement = Element.FindElement(by);
+ if (expectedElement != null)
+ {
+ return expectedElement;
+ }
+ }
+ catch (Exception)
+ {
+ // ignored
+ }
+
+ return expectedElement;
+ }
+
+ public ReadOnlyCollection FindElements(By by)
+ {
+ return Element.FindElements(by);
+ }
+
+ public void SetParrentField(IWebElement parrentField)
+ {
+ _parrentField = parrentField;
+ }
+
+ public void Clear()
+ {
+ Element.Clear();
+ }
+
+ public void SendKeys(string text)
+ {
+ Element.SendKeys(text);
+ }
+
+ public void Submit()
+ {
+ Element.Submit();
+ }
+
+ public void Click()
+ {
+ Element.Click();
+ }
+
+ public string GetAttribute(string attributeName)
+ {
+ return Element.GetAttribute(attributeName);
+ }
+
+ public string GetProperty(string propertyName)
+ {
+ return Element.GetProperty(propertyName);
+ }
+
+ public string GetCssValue(string propertyName)
+ {
+ return Element.GetCssValue(propertyName);
+ }
+
+ public string TagName => Element.TagName;
+ public string Text => Element.Text;
+ public bool Enabled => Element.Enabled;
+ public bool Selected => Element.Selected;
+ public Point Location => Element.Location;
+ public Size Size => Element.Size;
+ public bool Displayed => Element.Displayed;
+ public IWebElement WrappedElement => Element;
+
+
+ ///
+ /// Search for IwebElement in ShadowDOM.
+ ///
+ ///
+ ///
+ /// If rootElement is defined then the search is performed inside rootElement
+ ///
+ ///
+ public IWebElement SearchElement(How how, string usingString, IWebElement rootElement = null)
+ {
+ List elementsList;
+ elementsList = SearchElements(how, usingString, rootElement);
+ if (elementsList.Count > 0)
+ {
+ return elementsList.First();
+ }
+
+ throw new NoSuchElementException($"Failed to find element in shadowDom By:{_by}");
+ }
+
+ public IWebElement SearchElement(By by, IWebElement rooElement = null)
+ {
+ How how = GetFindMethod(by);
+ string usingString = GetUsingString(how, by);
+ return SearchElement(how, usingString, rooElement);
+ }
+
+ public IWebElement SearchElement(IWebElement rooElement = null)
+ {
+ How how = GetFindMethod(_by);
+ string usingString = GetUsingString(how, _by);
+ return SearchElement(how, usingString, rooElement);
+ }
+
+ public List SearchElements(How how, string usingstring, IWebElement rootElement = null)
+ {
+ List elementsList = new List();
+ switch (how)
+ {
+ case How.CssSelector:
+ elementsList = SearchElementsByCss(rootElement, usingstring);
+ break;
+ case How.XPath:
+ elementsList = SearchElementByXpath(rootElement, usingstring);
+ if (elementsList != null && elementsList.Count > 0)
+ {
+ foreach (RemoteWebElement element in elementsList)
+ {
+ try
+ {
+ IWebElement webElement = element.FindElement(_by);
+ elementsList.Add((RemoteWebElement)webElement);
+ }
+ catch (Exception)
+ {
+ //ignored
+ }
+ }
+ }
+
+ break;
+ case How.ClassName:
+ throw new InvalidSelectorException("How.ClassName is not supported yet");
+ case How.Id:
+ elementsList = SearchElementById(rootElement, usingstring);
+ break;
+
+ }
+
+ if (elementsList != null && elementsList.Count.Equals(0))
+ {
+ throw new NoSuchElementException($"Failed to find elements in shadowDom By:{_by}");
+ }
+
+ return elementsList;
+ }
+
+ public List SearchElements(By by, IWebElement rootField = null)
+ {
+ How how = GetFindMethod(by);
+ string usingString = GetUsingString(how, by);
+ return SearchElements(how, usingString, rootField);
+ }
+
+ public List SearchElements(IWebElement rootField = null)
+ {
+ return SearchElements(_by, rootField);
+ }
+
+ private List FilterRezultsList(IReadOnlyCollection
+
+
+
+
+
+
+
+
+
+
+ Shadow #2
+
+
+
+
+
+ Dummy text:
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
+
+
+
+
+
+
+
+ Shadow #3
+
+
+
+
+
+ Dummy text:
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Vaft.SeleniumNunitTests/Tests/ShadowDomWebElementTests.cs b/Vaft.SeleniumNunitTests/Tests/ShadowDomWebElementTests.cs
new file mode 100644
index 0000000..195a4e9
--- /dev/null
+++ b/Vaft.SeleniumNunitTests/Tests/ShadowDomWebElementTests.cs
@@ -0,0 +1,45 @@
+using System;
+using System.IO;
+using System.Reflection;
+using NUnit.Framework;
+using Vaft.Framework.Core;
+using Vaft.PageObjects.Pages;
+
+namespace Vaft.SeleniumNunitTests.Tests
+{
+ public class ShadowDomWebElementTests:TestBase
+ {
+ private readonly string DemoPage = "Resources\\WebComponentsDemoPage.html";
+ private WebComponentsDemoPage _demoPage;
+
+
+ [SetUp]
+ public void SetUp()
+ {
+ _demoPage= new WebComponentsDemoPage(Driver);
+ Driver.Navigate().GoToUrl("file:///"+Path.Combine(GetExecutingAssemblyPath(), DemoPage));
+ }
+
+
+ [Test]
+ public void VerifyPageValues()
+ {
+ string text1 = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.";
+ string text2 ="Lorem Ipsum is simply dummy text of the printing and typesetting industry.Lorem Ipsum is simply dummy text of the printing and typesetting industry.Lorem Ipsum is simply dummy text of the printing and typesetting industry.";
+
+ Assert.AreEqual( "987777",_demoPage.GetShadow1InputTwoFieldValue());
+ Assert.AreEqual(text1,_demoPage.GetShadow2DummyTextValue());
+ Assert.AreEqual("2133546",_demoPage.GetShadow3InputFieldSub3TwoValue());
+ Assert.AreEqual(text1,_demoPage.GetShadow3DummyTextValue());
+ Assert.AreEqual("5",_demoPage.GetShadow22InputFieldSub2TwoValue());
+ Assert.AreEqual(text2,_demoPage.GetShadow22DummyTextValue());
+ }
+
+ private string GetExecutingAssemblyPath()
+ {
+ var assemblyFile = new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath;
+ var path = Path.GetDirectoryName(assemblyFile);
+ return Uri.UnescapeDataString(path);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vaft.SeleniumNunitTests/Vaft.SeleniumNunitTests.csproj b/Vaft.SeleniumNunitTests/Vaft.SeleniumNunitTests.csproj
index 91dd4ec..b3d8cbe 100644
--- a/Vaft.SeleniumNunitTests/Vaft.SeleniumNunitTests.csproj
+++ b/Vaft.SeleniumNunitTests/Vaft.SeleniumNunitTests.csproj
@@ -93,6 +93,7 @@
+
@@ -131,6 +132,9 @@
Always
+
+ Always
+