Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix glitches in WaitFor: NRE, monotonic clock, exception after success #21

Merged
merged 1 commit into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 21 additions & 31 deletions src/Core/Riganti.Selenium.Core/BrowserWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -589,34 +589,28 @@ public IBrowserWrapper WaitFor(Func<bool> condition, int timeout, string failure
{
throw new NullReferenceException("Condition cannot be null.");
}
var now = DateTime.UtcNow;
var stopwatch = Stopwatch.StartNew();

bool isConditionMet = false;
Exception ex = null;
do
while (true)
{
try
{
isConditionMet = condition();
if (condition())
return this;
}
catch (StaleElementReferenceException)
catch (StaleElementReferenceException) when (ignoreCertainException)
{
if (!ignoreCertainException)
throw;
}
catch (InvalidElementStateException)
catch (InvalidElementStateException) when (ignoreCertainException)
{
if (!ignoreCertainException)
throw;
}

if (DateTime.UtcNow.Subtract(now).TotalMilliseconds > timeout)
if (stopwatch.ElapsedMilliseconds > timeout)
{
throw new WaitBlockException(failureMessage);
throw new WaitBlockException(failureMessage ?? "Condition returned false after timeout expired.");
}
Wait(checkInterval);
} while (!isConditionMet);
return this;
}
}
/// <inheritdoc />

Expand Down Expand Up @@ -654,32 +648,28 @@ public IBrowserWrapper WaitFor(Action action, int timeout, int checkInterval = 3
{
throw new ArgumentNullException(nameof(action));
}
var now = DateTime.UtcNow;
var stopwatch = Stopwatch.StartNew();

Exception exceptionThrown = null;
do
while (true)
{
try
{
action();
exceptionThrown = null;
return this;
}
catch (Exception ex)
catch (Exception exceptionThrown)
{
exceptionThrown = ex;
}

if (DateTime.UtcNow.Subtract(now).TotalMilliseconds > timeout)
{
if (failureMessage != null)
if (stopwatch.ElapsedMilliseconds > timeout)
{
throw new WaitBlockException(failureMessage, exceptionThrown);
if (failureMessage != null)
{
throw new WaitBlockException(failureMessage, exceptionThrown);
}
throw;
}
throw exceptionThrown;
}
Wait(checkInterval);
} while (exceptionThrown != null);
return this;
}
}

public IElementWrapper WaitFor(Func<IBrowserWrapper, IElementWrapper> selector, WaitForOptions options = null)
Expand Down Expand Up @@ -788,4 +778,4 @@ protected IBrowserWrapper EvaluateBrowserCheck<TException>(IValidator<IBrowserWr
return this;
}
}
}
}
29 changes: 13 additions & 16 deletions src/Core/Riganti.Selenium.Core/ElementWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Riganti.Selenium.Core.Abstractions;
using Riganti.Selenium.Core.Abstractions.Exceptions;
using Riganti.Selenium.Core.Api;
using System.Diagnostics;

namespace Riganti.Selenium.Core
{
Expand Down Expand Up @@ -560,34 +561,30 @@ public IElementWrapper WaitFor(Func<IElementWrapper, bool> condition, int maxTim
{
throw new NullReferenceException("Condition cannot be null.");
}
var now = DateTime.UtcNow;

bool isConditionMet = false;
do
var stopwatch = Stopwatch.StartNew();

while (true)
{
try
{
isConditionMet = condition(this);
if (condition(this))
return this;
}
catch (StaleElementReferenceException)
catch (StaleElementReferenceException) when (ignoreCertainException)
{
if (!ignoreCertainException)
throw;
}
catch (InvalidElementStateException)
catch (InvalidElementStateException) when (ignoreCertainException)
{
if (!ignoreCertainException)
throw;
}

if (DateTime.UtcNow.Subtract(now).TotalMilliseconds > maxTimeout)
if (stopwatch.ElapsedMilliseconds > maxTimeout)
{
throw new WaitBlockException(failureMessage);
throw new WaitBlockException(failureMessage ?? "Condition returned false after timeout expired.");
}
Wait(checkInterval);
} while (!isConditionMet);

return this;
Wait(checkInterval);
}
}

public IElementWrapper WaitFor(Action<IElementWrapper> checkExpression, int maxTimeout, string failureMessage, int checkInterval = 30)
Expand Down Expand Up @@ -730,4 +727,4 @@ public bool HasCssClass(string cssClass)
return attr.Split(' ').Any(s => string.Equals(cssClass, s, StringComparison.OrdinalIgnoreCase));
}
}
}
}
29 changes: 15 additions & 14 deletions src/Core/Riganti.Selenium.Core/WaitForExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Riganti.Selenium.Core.Abstractions.Exceptions;
using System.Threading;
using System.Diagnostics;

namespace Riganti.Selenium.Core
{
Expand All @@ -12,26 +13,25 @@ public void WaitFor(Action condition, int timeout, string failureMessage, int ch
{
throw new NullReferenceException("Condition cannot be null.");
}
var now = DateTime.UtcNow;
var stopwatch = Stopwatch.StartNew();

bool isConditionMet = false;
do
while (true)
{
try
{
condition();
isConditionMet = true;
return;
}
catch (TestExceptionBase ex)
{
if (DateTime.UtcNow.Subtract(now).TotalMilliseconds > timeout)
if (stopwatch.ElapsedMilliseconds > timeout)
{
if (throwOriginal) throw;
else throw new WaitBlockException(failureMessage ?? ex.Message, ex);
}
}
Thread.Sleep(checkInterval);
} while (!isConditionMet);
}
}
public void WaitFor(Func<bool> condition, WaitForOptions options = null)
{
Expand All @@ -40,29 +40,30 @@ public void WaitFor(Func<bool> condition, WaitForOptions options = null)
{
throw new NullReferenceException("Condition cannot be null.");
}
var now = DateTime.UtcNow;
var stopwatch = Stopwatch.StartNew();

bool isConditionMet = false;
do
while (true)
{
try
{
isConditionMet = condition();
if (condition())
return;
}
catch (TestExceptionBase ex)
{
if (DateTime.UtcNow.Subtract(now).TotalMilliseconds > options.Timeout)
if (stopwatch.ElapsedMilliseconds > options.Timeout)
{
if (options.ThrowOriginalException) throw;
else throw new WaitBlockException(options.FailureMessage ?? ex.Message, ex);
}
}
if (DateTime.UtcNow.Subtract(now).TotalMilliseconds > options.Timeout)
if (stopwatch.ElapsedMilliseconds > options.Timeout)
{
throw new WaitBlockException(options.FailureMessage);
throw new WaitBlockException(options.FailureMessage ?? "Condition returned false after timeout expired.");
}

Thread.Sleep(options.CheckInterval);
} while (!isConditionMet);
}
}

/// <summary>
Expand Down
Loading