Skip to content

Commit 6905230

Browse files
authored
Extract interface from ConditionalWait (#55)
* Extract interface from ConditionalWait * Correct thrown exception type at CachedElementStateProvider
1 parent ac30708 commit 6905230

File tree

17 files changed

+197
-39
lines changed

17 files changed

+197
-39
lines changed

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Applications/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public virtual IServiceCollection ConfigureServices(IServiceCollection services,
4040
services.AddSingleton<ILocalizedLogger, LocalizedLogger>();
4141
services.AddSingleton<IElementActionRetrier, ElementActionRetrier>();
4242

43-
services.AddTransient<ConditionalWait>();
43+
services.AddTransient<IConditionalWait, ConditionalWait>();
4444
services.AddTransient<IElementFinder, ElementFinder>();
4545
services.AddTransient<IElementFactory, ElementFactory>();
4646
return services;

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

Lines changed: 51 additions & 3 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/CachedElementStateProvider.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ namespace Aquality.Selenium.Core.Elements
1111
public class CachedElementStateProvider : IElementStateProvider
1212
{
1313
private readonly IElementCacheHandler elementCacheHandler;
14-
private readonly ConditionalWait conditionalWait;
14+
private readonly IConditionalWait conditionalWait;
1515
private readonly By locator;
1616

17-
public CachedElementStateProvider(By locator, ConditionalWait conditionalWait, IElementCacheHandler elementCacheHandler)
17+
public CachedElementStateProvider(By locator, IConditionalWait conditionalWait, IElementCacheHandler elementCacheHandler)
1818
{
1919
this.elementCacheHandler = elementCacheHandler;
2020
this.conditionalWait = conditionalWait;
@@ -50,7 +50,15 @@ protected virtual bool TryInvokeFunction(Func<IWebElement, bool> func)
5050
public virtual void WaitForClickable(TimeSpan? timeout = null)
5151
{
5252
var errorMessage = $"Element {locator} has not become clickable after timeout.";
53-
conditionalWait.WaitForTrue(() => IsClickable, timeout, message: errorMessage);
53+
try
54+
{
55+
conditionalWait.WaitForTrue(() => IsClickable, timeout, message: errorMessage);
56+
}
57+
catch (TimeoutException e)
58+
{
59+
throw new WebDriverTimeoutException(e.Message, e);
60+
}
61+
5462
}
5563

5664
public virtual bool WaitForDisplayed(TimeSpan? timeout = null)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ protected virtual IElementCacheHandler Cache
5353

5454
protected abstract IElementCacheConfiguration CacheConfiguration { get; }
5555

56-
protected abstract ConditionalWait ConditionalWait { get; }
56+
protected abstract IConditionalWait ConditionalWait { get; }
5757

5858
protected abstract string ElementType { get; }
5959

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ public class ElementFactory : IElementFactory
1717
{
1818
private const string ByXpathIdentifier = "By.XPath";
1919

20-
public ElementFactory(ConditionalWait conditionalWait, IElementFinder elementFinder, ILocalizationManager localizationManager)
20+
public ElementFactory(IConditionalWait conditionalWait, IElementFinder elementFinder, ILocalizationManager localizationManager)
2121
{
2222
ConditionalWait = conditionalWait;
2323
ElementFinder = elementFinder;
2424
LocalizationManager = localizationManager;
2525
}
2626

27-
protected ConditionalWait ConditionalWait { get; }
27+
protected IConditionalWait ConditionalWait { get; }
2828

2929
protected IElementFinder ElementFinder { get; }
3030

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ namespace Aquality.Selenium.Core.Elements
1414
/// </summary>
1515
public class ElementFinder : IElementFinder
1616
{
17-
public ElementFinder(ILocalizedLogger logger, ConditionalWait conditionalWait)
17+
public ElementFinder(ILocalizedLogger logger, IConditionalWait conditionalWait)
1818
{
1919
Logger = logger;
2020
ConditionalWait = conditionalWait;
2121
}
2222

2323
private ILocalizedLogger Logger { get; }
2424

25-
private ConditionalWait ConditionalWait { get; }
25+
private IConditionalWait ConditionalWait { get; }
2626

2727
public virtual IWebElement FindElement(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
2828
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ public class ElementStateProvider : IElementStateProvider
1010
{
1111
private readonly By elementLocator;
1212

13-
public ElementStateProvider(By elementLocator, ConditionalWait conditionalWait, IElementFinder elementFinder)
13+
public ElementStateProvider(By elementLocator, IConditionalWait conditionalWait, IElementFinder elementFinder)
1414
{
1515
this.elementLocator = elementLocator;
1616
ConditionalWait = conditionalWait;
1717
ElementFinder = elementFinder;
1818
}
1919

20-
private ConditionalWait ConditionalWait { get; }
20+
private IConditionalWait ConditionalWait { get; }
2121

2222
private IElementFinder ElementFinder { get; }
2323

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ namespace Aquality.Selenium.Core.Elements
1414
/// </summary>
1515
public class RelativeElementFinder : ElementFinder
1616
{
17-
public RelativeElementFinder(ILocalizedLogger logger, ConditionalWait conditionalWait, Func<ISearchContext> searchContextSupplier)
17+
public RelativeElementFinder(ILocalizedLogger logger, IConditionalWait conditionalWait, Func<ISearchContext> searchContextSupplier)
1818
: base(logger, conditionalWait)
1919
{
2020
ConditionalWait = conditionalWait;
2121
SearchContextSupplier = searchContextSupplier;
2222
}
2323

24-
private ConditionalWait ConditionalWait { get; }
24+
private IConditionalWait ConditionalWait { get; }
2525

2626
private Func<ISearchContext> SearchContextSupplier { get; }
2727

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Waitings/ConditionalWait.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
namespace Aquality.Selenium.Core.Waitings
1313
{
1414
/// <summary>
15-
/// This class is using for waiting any conditions.
15+
/// This class is used for waiting any conditions.
1616
/// </summary>
17-
public class ConditionalWait
17+
public class ConditionalWait : IConditionalWait
1818
{
1919
private readonly ITimeoutConfiguration timeoutConfiguration;
2020
private readonly IServiceProvider serviceProvider;
@@ -68,18 +68,15 @@ public T WaitFor<T>(Func<IWebDriver, T> condition, TimeSpan? timeout = null, Tim
6868
/// <param name="condition">Predicate for waiting</param>
6969
/// <param name="timeout">Condition timeout. Default value is <see cref="ITimeoutConfiguration.Condition"/></param>
7070
/// <param name="pollingInterval">Condition check interval. Default value is <see cref="ITimeoutConfiguration.PollingInterval"/></param>
71+
/// <param name="exceptionsToIgnore">Possible exceptions that have to be ignored. </param>
7172
/// <returns>True if condition satisfied and false otherwise.</returns>
72-
public bool WaitFor(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null)
73+
public bool WaitFor(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null, IList<Type> exceptionsToIgnore = null)
7374
{
74-
try
75+
return IsConditionSatisfied(() =>
7576
{
76-
WaitForTrue(condition, timeout, pollingInterval);
77+
WaitForTrue(condition, timeout, pollingInterval, exceptionsToIgnore: exceptionsToIgnore);
7778
return true;
78-
}
79-
catch (TimeoutException)
80-
{
81-
return false;
82-
}
79+
}, new List<Type> { typeof(TimeoutException) });
8380
}
8481

8582
/// <summary>
@@ -89,8 +86,9 @@ public bool WaitFor(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? po
8986
/// <param name="timeout">Condition timeout. Default value is <see cref="ITimeoutConfiguration.Condition"/></param>
9087
/// <param name="pollingInterval">Condition check interval. Default value is <see cref="ITimeoutConfiguration.PollingInterval"/></param>
9188
/// <param name="message">Part of error message in case of Timeout exception</param>
89+
/// <param name="exceptionsToIgnore">Possible exceptions that have to be ignored. </param>
9290
/// <exception cref="TimeoutException">Throws when timeout exceeded and condition not satisfied.</exception>
93-
public void WaitForTrue(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null, string message = null)
91+
public void WaitForTrue(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null, string message = null, IList<Type> exceptionsToIgnore = null)
9492
{
9593
if (condition == null)
9694
{
@@ -102,7 +100,7 @@ public void WaitForTrue(Func<bool> condition, TimeSpan? timeout = null, TimeSpan
102100
var stopwatch = Stopwatch.StartNew();
103101
while (true)
104102
{
105-
if (condition())
103+
if (IsConditionSatisfied(condition, exceptionsToIgnore ?? new List<Type>()))
106104
{
107105
return;
108106
}
@@ -122,6 +120,23 @@ public void WaitForTrue(Func<bool> condition, TimeSpan? timeout = null, TimeSpan
122120
}
123121
}
124122

123+
private bool IsConditionSatisfied(Func<bool> condition, IList<Type> exceptionsToIgnore)
124+
{
125+
try
126+
{
127+
return condition();
128+
}
129+
catch (Exception exception)
130+
{
131+
if (exceptionsToIgnore.Any(type => type.IsAssignableFrom(exception.GetType())))
132+
{
133+
return false;
134+
}
135+
136+
throw;
137+
}
138+
}
139+
125140
private TimeSpan ResolveConditionTimeout(TimeSpan? timeout)
126141
{
127142
return timeout ?? timeoutConfiguration.Condition;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using Aquality.Selenium.Core.Configurations;
2+
using OpenQA.Selenium;
3+
using System;
4+
using System.Collections.Generic;
5+
6+
namespace Aquality.Selenium.Core.Waitings
7+
{
8+
/// <summary>
9+
/// Utility used to wait for some condition.
10+
/// </summary>
11+
public interface IConditionalWait
12+
{
13+
/// <summary>
14+
/// Wait for some condition within timeout.
15+
/// </summary>
16+
/// <param name="condition">Predicate for waiting</param>
17+
/// <param name="timeout">Condition timeout. Default value is <see cref="ITimeoutConfiguration.Condition"/></param>
18+
/// <param name="pollingInterval">Condition check interval. Default value is <see cref="ITimeoutConfiguration.PollingInterval"/></param>
19+
/// <param name="exceptionsToIgnore">Possible exceptions that have to be ignored. </param>
20+
/// <returns>True if condition satisfied and false otherwise.</returns>
21+
bool WaitFor(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null, IList<Type> exceptionsToIgnore = null);
22+
23+
/// <summary>
24+
/// Wait for some object from condition with timeout using Selenium WebDriver.
25+
/// </summary>
26+
/// <typeparam name="T">Type of object which is waiting for</typeparam>
27+
/// <param name="condition">Function for waiting</param>
28+
/// <param name="timeout">Condition timeout. Default value is <see cref="ITimeoutConfiguration.Condition"/></param>
29+
/// <param name="pollingInterval">Condition check interval. Default value is <see cref="ITimeoutConfiguration.PollingInterval"/></param>
30+
/// <param name="message">Part of error message in case of Timeout exception</param>
31+
/// <param name="exceptionsToIgnore">Possible exceptions that have to be ignored. Handles <see cref="StaleElementReferenceException"/> by default.</param>
32+
/// <returns>Condition result which is waiting for.</returns>
33+
/// <exception cref="WebDriverTimeoutException">Throws when timeout exceeded and condition not satisfied.</exception>
34+
T WaitFor<T>(Func<IWebDriver, T> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null, string message = null, IList<Type> exceptionsToIgnore = null);
35+
36+
/// <summary>
37+
/// Wait for some condition within timeout.
38+
/// </summary>
39+
/// <param name="condition">Predicate for waiting</param>
40+
/// <param name="timeout">Condition timeout. Default value is <see cref="ITimeoutConfiguration.Condition"/></param>
41+
/// <param name="pollingInterval">Condition check interval. Default value is <see cref="ITimeoutConfiguration.PollingInterval"/></param>
42+
/// <param name="message">Part of error message in case of Timeout exception</param>
43+
/// <param name="exceptionsToIgnore">Possible exceptions that have to be ignored. </param>
44+
/// <exception cref="TimeoutException">Throws when timeout exceeded and condition not satisfied.</exception>
45+
void WaitForTrue(Func<bool> condition, TimeSpan? timeout = null, TimeSpan? pollingInterval = null, string message = null, IList<Type> exceptionsToIgnore = null);
46+
}
47+
}

0 commit comments

Comments
 (0)