Skip to content

Commit d96e467

Browse files
authored
Implement RelativeElementFinder (#40)
* Implement RelativeElementFinder * Make ElementFactory's methods to be virtual
1 parent 8c2ce82 commit d96e467

File tree

6 files changed

+241
-54
lines changed

6 files changed

+241
-54
lines changed

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Aquality.Selenium.Core.xml

Lines changed: 152 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Elements/ElementFactory.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,30 +37,27 @@ public ElementFactory(ConditionalWait conditionalWait, IElementFinder elementFin
3737
/// <returns>Dictionary where key is interface and value is its implementation.</returns>
3838
protected virtual IDictionary<Type, Type> ElementTypesMap => new Dictionary<Type, Type>();
3939

40-
public T FindChildElement<T>(IElement parentElement, By childLocator, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed) where T : IElement
40+
public virtual T FindChildElement<T>(IElement parentElement, By childLocator, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed) where T : IElement
4141
{
4242
var elementSupplier = ResolveSupplier(supplier);
4343
return elementSupplier(new ByChained(parentElement.Locator, childLocator), $"Child element of {parentElement.Name}", state);
4444
}
4545

46-
public IList<T> FindElements<T>(By locator, ElementSupplier<T> supplier = null, ElementsCount expectedCount = ElementsCount.Any, ElementState state = ElementState.Displayed) where T : IElement
46+
public virtual IList<T> FindElements<T>(By locator, ElementSupplier<T> supplier = null, ElementsCount expectedCount = ElementsCount.Any, ElementState state = ElementState.Displayed) where T : IElement
4747
{
4848
var elementSupplier = ResolveSupplier(supplier);
4949
switch (expectedCount)
5050
{
5151
case ElementsCount.Zero:
52-
ConditionalWait.WaitFor(driver => !driver.FindElements(locator).Any(
53-
webElement => state == ElementState.ExistsInAnyState || webElement.Displayed),
52+
ConditionalWait.WaitForTrue(() => !ElementFinder.FindElements(locator, state, TimeSpan.Zero).Any(),
5453
message: LocalizationManager.GetLocalizedMessage("loc.elements.found.but.should.not", locator.ToString(), state.ToString()));
5554
break;
5655
case ElementsCount.MoreThenZero:
57-
ConditionalWait.WaitFor(driver => driver.FindElements(locator).Any(
58-
webElement => state == ElementState.ExistsInAnyState || webElement.Displayed),
56+
ConditionalWait.WaitForTrue(() => ElementFinder.FindElements(locator, state, TimeSpan.Zero).Any(),
5957
message: LocalizationManager.GetLocalizedMessage("loc.no.elements.found.by.locator", locator.ToString()));
6058
break;
6159
case ElementsCount.Any:
62-
ConditionalWait.WaitFor(driver => driver.FindElements(locator),
63-
message: LocalizationManager.GetLocalizedMessage("loc.search.of.elements.failed", locator.ToString()));
60+
ConditionalWait.WaitFor(() => ElementFinder.FindElements(locator, state, TimeSpan.Zero) != null);
6461
break;
6562
default:
6663
throw new ArgumentOutOfRangeException($"No such expected value: {expectedCount}");
@@ -75,7 +72,7 @@ public IList<T> FindElements<T>(By locator, ElementSupplier<T> supplier = null,
7572
return elements.ToList();
7673
}
7774

78-
public T GetCustomElement<T>(ElementSupplier<T> elementSupplier, By locator, string name, ElementState state = ElementState.Displayed) where T : IElement
75+
public virtual T GetCustomElement<T>(ElementSupplier<T> elementSupplier, By locator, string name, ElementState state = ElementState.Displayed) where T : IElement
7976
{
8077
return elementSupplier(locator, name, state);
8178
}

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Elements/ElementFinder.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,18 @@ public ElementFinder(ILocalizedLogger logger, ConditionalWait conditionalWait)
2424

2525
private ConditionalWait ConditionalWait { get; }
2626

27-
public IWebElement FindElement(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
27+
public virtual IWebElement FindElement(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
2828
{
2929
var desiredState = ResolveState(state);
3030
return FindElement(locator, desiredState.ElementStateCondition, desiredState.StateName, timeout);
3131
}
3232

33-
public IWebElement FindElement(By locator, Func<IWebElement, bool> elementStateCondition, TimeSpan? timeout = null)
33+
public virtual IWebElement FindElement(By locator, Func<IWebElement, bool> elementStateCondition, TimeSpan? timeout = null)
3434
{
3535
return FindElement(locator, elementStateCondition, "desired", timeout);
3636
}
3737

38-
private IWebElement FindElement(By locator, Func<IWebElement, bool> elementStateCondition, string stateName, TimeSpan? timeout = null)
38+
public virtual IWebElement FindElement(By locator, Func<IWebElement, bool> elementStateCondition, string stateName, TimeSpan? timeout = null)
3939
{
4040
var desiredState = new DesiredState(elementStateCondition, stateName)
4141
{
@@ -45,14 +45,14 @@ private IWebElement FindElement(By locator, Func<IWebElement, bool> elementState
4545
return FindElements(locator, desiredState, timeout).First();
4646
}
4747

48-
public ReadOnlyCollection<IWebElement> FindElements(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
48+
public virtual ReadOnlyCollection<IWebElement> FindElements(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
4949
{
5050
var elementStateCondition = ResolveState(state);
5151
elementStateCondition.IsCatchingTimeoutException = true;
5252
return FindElements(locator, elementStateCondition, timeout);
5353
}
5454

55-
public ReadOnlyCollection<IWebElement> FindElements(By locator, Func<IWebElement, bool> elementStateCondition, TimeSpan? timeout = null)
55+
public virtual ReadOnlyCollection<IWebElement> FindElements(By locator, Func<IWebElement, bool> elementStateCondition, TimeSpan? timeout = null)
5656
{
5757
var desiredState = new DesiredState(elementStateCondition, "desired")
5858
{
@@ -61,7 +61,7 @@ public ReadOnlyCollection<IWebElement> FindElements(By locator, Func<IWebElement
6161
return FindElements(locator, desiredState, timeout);
6262
}
6363

64-
public ReadOnlyCollection<IWebElement> FindElements(By locator, DesiredState desiredState, TimeSpan? timeout = null)
64+
public virtual ReadOnlyCollection<IWebElement> FindElements(By locator, DesiredState desiredState, TimeSpan? timeout = null)
6565
{
6666
var foundElements = new List<IWebElement>();
6767
var resultElements = new List<IWebElement>();
@@ -81,7 +81,7 @@ public ReadOnlyCollection<IWebElement> FindElements(By locator, DesiredState des
8181
return resultElements.AsReadOnly();
8282
}
8383

84-
private void HandleTimeoutException(WebDriverTimeoutException ex, DesiredState desiredState, By locator, List<IWebElement> foundElements)
84+
protected virtual void HandleTimeoutException(WebDriverTimeoutException ex, DesiredState desiredState, By locator, List<IWebElement> foundElements)
8585
{
8686
var message = $"No elements with locator '{locator.ToString()}' were found in {desiredState.StateName} state";
8787
if (desiredState.IsCatchingTimeoutException)
@@ -110,7 +110,7 @@ private void HandleTimeoutException(WebDriverTimeoutException ex, DesiredState d
110110
}
111111
}
112112

113-
private DesiredState ResolveState(ElementState state)
113+
protected virtual DesiredState ResolveState(ElementState state)
114114
{
115115
Func<IWebElement, bool> elementStateCondition;
116116
switch (state)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using Aquality.Selenium.Core.Elements.Interfaces;
2+
using Aquality.Selenium.Core.Localization;
3+
using Aquality.Selenium.Core.Waitings;
4+
using OpenQA.Selenium;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Collections.ObjectModel;
8+
using System.Linq;
9+
10+
namespace Aquality.Selenium.Core.Elements
11+
{
12+
/// <summary>
13+
/// Implementation of <see cref="IElementFinder"/> for a relative <see cref="ISearchContext"/> supplier
14+
/// </summary>
15+
public class RelativeElementFinder : ElementFinder
16+
{
17+
public RelativeElementFinder(ILocalizedLogger logger, ConditionalWait conditionalWait, Func<ISearchContext> searchContextSupplier)
18+
: base(logger, conditionalWait)
19+
{
20+
ConditionalWait = conditionalWait;
21+
SearchContextSupplier = searchContextSupplier;
22+
}
23+
24+
private ConditionalWait ConditionalWait { get; }
25+
26+
private Func<ISearchContext> SearchContextSupplier { get; }
27+
28+
public override ReadOnlyCollection<IWebElement> FindElements(By locator, DesiredState desiredState, TimeSpan? timeout = null)
29+
{
30+
var foundElements = new List<IWebElement>();
31+
var resultElements = new List<IWebElement>();
32+
try
33+
{
34+
ConditionalWait.WaitFor(() =>
35+
{
36+
foundElements = SearchContextSupplier().FindElements(locator).ToList();
37+
resultElements = foundElements.Where(desiredState.ElementStateCondition).ToList();
38+
return resultElements.Any();
39+
}, timeout);
40+
}
41+
catch (WebDriverTimeoutException ex)
42+
{
43+
HandleTimeoutException(ex, desiredState, locator, foundElements);
44+
}
45+
return resultElements.AsReadOnly();
46+
}
47+
}
48+
}

Aquality.Selenium.Core/tests/Aquality.Selenium.Core.Tests/Applications/Browser/FindElementsTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void Should_BePossibleTo_FindElements_ForNotExistsElements(ElementsCount
6060
[TestCase(ElementsCount.Zero, ElementState.ExistsInAnyState)]
6161
public void Should_BeImpossibleTo_FindDisplayedElements_WithWrongArguments(ElementsCount count, ElementState state)
6262
{
63-
Assert.Throws<WebDriverTimeoutException>(
63+
Assert.Throws<TimeoutException>(
6464
() => elementFactory.FindElements<Label>(DisplayedElementsLoc, expectedCount: count, state: state),
6565
$"Tried to find elements with expected count '{count}' and state '{state}'");
6666
}
@@ -69,7 +69,7 @@ public void Should_BeImpossibleTo_FindDisplayedElements_WithWrongArguments(Eleme
6969
[TestCase(ElementsCount.Zero, ElementState.ExistsInAnyState)]
7070
public void Should_BeImpossibleTo_FindHiddenElements_WithWrongArguments(ElementsCount count, ElementState state)
7171
{
72-
Assert.Throws<WebDriverTimeoutException>(
72+
Assert.Throws<TimeoutException>(
7373
() => elementFactory.FindElements<Label>(HiddenElementsLoc, expectedCount: count, state: state),
7474
$"Tried to find elements with expected count '{count}' and state '{state}'");
7575
}
@@ -78,7 +78,7 @@ public void Should_BeImpossibleTo_FindHiddenElements_WithWrongArguments(Elements
7878
[TestCase(ElementsCount.MoreThenZero, ElementState.ExistsInAnyState)]
7979
public void Should_BeImpossibleTo_FindNotExistElements_WithWrongArguments(ElementsCount count, ElementState state)
8080
{
81-
Assert.Throws<WebDriverTimeoutException>(
81+
Assert.Throws<TimeoutException>(
8282
() => elementFactory.FindElements<Label>(NotExistElementLoc, expectedCount: count, state: state),
8383
$"Tried to find elements with expected count '{count}' and state '{state}'");
8484
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Aquality.Selenium.Core.Elements;
2+
using Aquality.Selenium.Core.Elements.Interfaces;
3+
using Aquality.Selenium.Core.Localization;
4+
using Aquality.Selenium.Core.Tests.Applications.WindowsApp.Locators;
5+
using Aquality.Selenium.Core.Waitings;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using NUnit.Framework;
8+
9+
namespace Aquality.Selenium.Core.Tests.Applications.WindowsApp
10+
{
11+
public class RelativeElementFinderTests : TestWithApplication
12+
{
13+
private IElementFinder ElementFinder => new RelativeElementFinder(
14+
AqualityServices.ServiceProvider.GetRequiredService<ILocalizedLogger>(),
15+
AqualityServices.ServiceProvider.GetRequiredService<ConditionalWait>(),
16+
() => AqualityServices.Application.Driver.FindElement(CalculatorWindow.WindowLocator));
17+
18+
[Test]
19+
public void Should_FindChildElements_ViaRelativeElementFinder()
20+
{
21+
Assert.IsNotNull(ElementFinder.FindElement(CalculatorWindow.OneButton));
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)