Skip to content

Commit

Permalink
[Selenium 4] ShadowRoot functionality wrapper (#211) +semver: feature
Browse files Browse the repository at this point in the history
* Implemented ShadowRoot functionality wrapper +semver: feature
  • Loading branch information
mialeska authored Jan 31, 2022
1 parent 123b866 commit 3157da0
Show file tree
Hide file tree
Showing 15 changed files with 263 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</PropertyGroup>

<ItemGroup>
<None Remove="Resources\JavaScripts\ExpandShadowRoot.js" />
<None Remove="Resources\Localization\be.json" />
<None Remove="Resources\Localization\en.json" />
<None Remove="Resources\Localization\ru.json" />
Expand All @@ -43,6 +44,7 @@
<EmbeddedResource Include="Resources\JavaScripts\GetComboBoxSelectedText.js" />
<EmbeddedResource Include="Resources\JavaScripts\GetComboBoxTexts.js" />
<EmbeddedResource Include="Resources\JavaScripts\GetElementByXPath.js" />
<EmbeddedResource Include="Resources\JavaScripts\ExpandShadowRoot.js" />
<EmbeddedResource Include="Resources\JavaScripts\GetElementText.js" />
<EmbeddedResource Include="Resources\JavaScripts\GetElementXPath.js" />
<EmbeddedResource Include="Resources\JavaScripts\GetTextFirstChild.js" />
Expand Down
55 changes: 51 additions & 4 deletions Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public enum JavaScript
SetValue,
GetViewPortCoordinates,
OpenNewTab,
OpenInNewTab
OpenInNewTab,
ExpandShadowRoot
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
using System.Linq;
using Aquality.Selenium.Browsers;
using Aquality.Selenium.Configurations;
using Aquality.Selenium.Core.Elements;
using Aquality.Selenium.Core.Localization;
using Aquality.Selenium.Core.Utilities;
using Aquality.Selenium.Elements.Interfaces;
using OpenQA.Selenium;

namespace Aquality.Selenium.Elements.Actions
{
Expand All @@ -34,6 +36,34 @@ public JsActions(IElement element, string elementType, ILocalizedLogger logger,

protected ILocalizedLogger Logger { get; }

/// <summary>
/// Expands shadow root.
/// </summary>
/// <returns><see cref="ShadowRoot"/> search context.</returns>
public ShadowRoot ExpandShadowRoot()
{
LogElementAction("loc.shadowroot.expand.js");
return ExecuteScript<ShadowRoot>(JavaScript.ExpandShadowRoot);
}

/// <summary>
/// Finds element in the shadow root of the current element.
/// </summary>
/// <typeparam name="T">Type of the target element that has to implement <see cref="IElement"/>.</typeparam>
/// <param name="locator">Locator of the target element.
/// Note that some browsers don't support XPath locator for shadow elements (e.g. Chrome).</param>
/// <param name="name">Name of the target element.</param>
/// <param name="supplier">Delegate that defines constructor of element.</param>
/// <param name="state">State of the target element.</param>
/// <returns>Instance of element.</returns>
public T FindElementInShadowRoot<T>(By locator, string name, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed)
where T : IElement
{
var shadowRootRelativeFinder = new RelativeElementFinder(Logger, AqualityServices.ConditionalWait, ExpandShadowRoot);
var shadowRootFactory = new ElementFactory(AqualityServices.ConditionalWait, shadowRootRelativeFinder, AqualityServices.Get<ILocalizationManager>());
return shadowRootFactory.Get(locator, name, supplier, state);
}

/// <summary>
/// Perfroms click on element and waits for page is loaded.
/// </summary>
Expand Down
19 changes: 18 additions & 1 deletion Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ protected Element(By locator, string name, ElementState state) : base(locator, n

protected virtual IElementFactory CustomFactory => AqualityServices.Get<IElementFactory>();

protected override ICoreElementFinder Finder => AqualityServices.Get<ICoreElementFinder>();
protected internal virtual ICoreElementFinder CustomFinder { get; internal set; } = AqualityServices.Get<ICoreElementFinder>();

protected override ICoreElementFinder Finder => CustomFinder;

protected override IElementCacheConfiguration CacheConfiguration => AqualityServices.Get<IElementCacheConfiguration>();

Expand Down Expand Up @@ -125,5 +127,20 @@ public void SendKey(Key key)
.FirstOrDefault(field => field.Name == key.ToString())?.GetValue(null).ToString();
DoWithRetry(() => GetElement().SendKeys(keysString));
}

public ShadowRoot ExpandShadowRoot()
{
LogElementAction("loc.shadowroot.expand");
var shadowRoot = (ShadowRoot)GetElement().GetShadowRoot();
return shadowRoot;
}

public T FindElementInShadowRoot<T>(By locator, string name, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed)
where T : IElement
{
var shadowRootRelativeFinder = new RelativeElementFinder(LocalizedLogger, ConditionalWait, ExpandShadowRoot);
var shadowRootFactory = new ElementFactory(ConditionalWait, shadowRootRelativeFinder, LocalizationManager);
return shadowRootFactory.Get(locator, name, supplier, state);
}
}
}
38 changes: 31 additions & 7 deletions Aquality.Selenium/src/Aquality.Selenium/Elements/ElementFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,37 +34,61 @@ public ElementFactory(IConditionalWait conditionalWait, IElementFinder elementFi

public IButton GetButton(By locator, string name, ElementState state = ElementState.Displayed)
{
return new Button(locator, name, state);
return ResolveSupplier<IButton>()(locator, name, state);
}

public ICheckBox GetCheckBox(By locator, string name, ElementState state = ElementState.Displayed)
{
return new CheckBox(locator, name, state);
return ResolveSupplier<ICheckBox>()(locator, name, state);
}

public IComboBox GetComboBox(By locator, string name, ElementState state = ElementState.Displayed)
{
return new ComboBox(locator, name, state);
return ResolveSupplier<IComboBox>()(locator, name, state);
}

public ILabel GetLabel(By locator, string name, ElementState state = ElementState.Displayed)
{
return new Label(locator, name, state);
return ResolveSupplier<ILabel>()(locator, name, state);
}

public ILink GetLink(By locator, string name, ElementState state = ElementState.Displayed)
{
return new Link(locator, name, state);
return ResolveSupplier<ILink>()(locator, name, state);
}

public IRadioButton GetRadioButton(By locator, string name, ElementState state = ElementState.Displayed)
{
return new RadioButton(locator, name, state);
return ResolveSupplier<IRadioButton>()(locator, name, state);
}

public ITextBox GetTextBox(By locator, string name, ElementState state = ElementState.Displayed)
{
return new TextBox(locator, name, state);
return ResolveSupplier<ITextBox>()(locator, name, state);
}

public T Get<T>(By locator, string name, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed) where T : Interfaces.IElement
{
return ResolveSupplier(supplier)(locator, name, state);
}

private ElementSupplier<T> ResolveSupplier<T>() where T : Interfaces.IElement
{
return ResolveSupplier<T>(null);
}

protected override ElementSupplier<T> ResolveSupplier<T>(ElementSupplier<T> supplier)
{
var baseSupplier = base.ResolveSupplier(supplier);
return (loc, name, state) =>
{
var element = baseSupplier.Invoke(loc, name, state);
if (element is Element baseElement)
{
baseElement.CustomFinder = ElementFinder;
}
return element;
};
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Aquality.Selenium.Elements.Actions;
using Aquality.Selenium.Core.Elements;
using Aquality.Selenium.Elements.Actions;
using OpenQA.Selenium;
using ICoreElement = Aquality.Selenium.Core.Elements.Interfaces.IElement;

namespace Aquality.Selenium.Elements.Interfaces
Expand All @@ -23,16 +25,16 @@ public interface IElement : ICoreElement
/// <summary>
/// Gets element text.
/// </summary>
/// <param name="highlightState">Should the element be hightlighted or not.
/// <param name="highlightState">Should the element be highlighted or not.
/// Default value is from configuration: <seealso cref="Configurations.IBrowserProfile.IsElementHighlightEnabled"/></param>
/// <returns>String representation of element text.</returns>
string GetText(HighlightState highlightState = HighlightState.Default);

/// <summary>
/// Gets element attribute value by its name.
/// </summary>
/// <param name="attr">Name of attrbiute</param>
/// <param name="highlightState">Should the element be hightlighted or not.
/// <param name="attr">Name of attribute</param>
/// <param name="highlightState">Should the element be highlighted or not.
/// Default value is from configuration: <seealso cref="Configurations.IBrowserProfile.IsElementHighlightEnabled"/></param>
/// <returns>Value of element attribute.</returns>
string GetAttribute(string attr, HighlightState highlightState = HighlightState.Default);
Expand All @@ -41,7 +43,7 @@ public interface IElement : ICoreElement
/// Gets css value of the element.
/// </summary>
/// <param name="propertyName">Name of css property</param>
/// <param name="highlightState">Should the element be hightlighted or not.
/// <param name="highlightState">Should the element be highlighted or not.
/// Default value is from configuration: <seealso cref="Configurations.IBrowserProfile.IsElementHighlightEnabled"/></param>
/// <returns>Value of element attribute.</returns>
string GetCssValue(string propertyName, HighlightState highlightState = HighlightState.Default);
Expand Down Expand Up @@ -72,5 +74,24 @@ public interface IElement : ICoreElement
/// </summary>
/// <param name="key"> Key for sending.</param>
void SendKey(Key key);

/// <summary>
/// Expands shadow root.
/// </summary>
/// <returns><see cref="ShadowRoot"/> search context.</returns>
ShadowRoot ExpandShadowRoot();

/// <summary>
/// Finds element in the shadow root of the current element.
/// </summary>
/// <typeparam name="T">Type of the target element that has to implement <see cref="IElement"/>.</typeparam>
/// <param name="locator">Locator of the target element.
/// Note that some browsers don't support XPath locator for shadow elements.</param>
/// <param name="name">Name of the target element.</param>
/// <param name="supplier">Delegate that defines constructor of element.</param>
/// <param name="state">State of the target element.</param>
/// <returns>Instance of element.</returns>
T FindElementInShadowRoot<T>(By locator, string name, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed)
where T : IElement;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,16 @@ public interface IElementFactory : ICoreElementFactory
/// <param name="state">Element state</param>
/// <returns>Instance of element that implements ITextBox interface</returns>
ITextBox GetTextBox(By locator, string name, ElementState state = ElementState.Displayed);

/// <summary>
/// Creates element that implements <typeparamref name="T"/> interface.
/// </summary>
/// <typeparam name="T">Type of child element that has to implement IElement.</typeparam>
/// <param name="locator">Base elements locator.</param>
/// <param name="name">Elements name.</param>
/// <param name="supplier">Delegate that defines constructor of element in case of custom element.</param>
/// <param name="state">Elements state.</param>
/// <returns></returns>
T Get<T>(By locator, string name, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed) where T : IElement;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return arguments[0].shadowRoot;
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@
"loc.browser.network.handler.response.add": "Дадаем апрацоўшчык сеткавых адказаў",
"loc.browser.network.handler.response.clear": "Ачышчаем апрацоўшчыкі сеткавых адказаў",
"loc.browser.network.monitoring.start": "Пачынаем сеткавы маніторынг",
"loc.browser.network.monitoring.stop": "Спыняем сеткавы маніторынг"
"loc.browser.network.monitoring.stop": "Спыняем сеткавы маніторынг",
"loc.shadowroot.expand": "Разварочваем дрэва схаваных элементаў",
"loc.shadowroot.expand.js": "Разварочваем дрэва схаваных элементаў праз JavaScript"
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@
"loc.browser.network.handler.response.add": "Adding Network Response handler",
"loc.browser.network.handler.response.clear": "Clearing Network Response handler",
"loc.browser.network.monitoring.start": "Starting Network Monitoring",
"loc.browser.network.monitoring.stop": "Stopping Network Monitoring"
"loc.browser.network.monitoring.stop": "Stopping Network Monitoring",
"loc.shadowroot.expand": "Expanding the Shadow Root",
"loc.shadowroot.expand.js": "Expanding the Shadow Root via JavaScript"
}
Loading

0 comments on commit 3157da0

Please sign in to comment.