如果值在一段时间后发生变化,则使用 WebDriverWait 等待
Using WebDriverWait to wait if value changes after some time
一段时间后,我正在使用 WebDriverWait
获取 WebElement
的值,但如果它没有改变,我不希望它失败,只获取当前值值并继续执行。
我正在 Web 中 运行 设置一个进程,该进程有一个 "process completed" 标签,我用它来检查它是否完成。在同一屏幕上,有一个 "elapsed time" 用于我需要阅读的过程,以报告 运行 该过程花费了多少时间。
问题是即使在 "process completed" 标签出现后,后端进程 运行ning 也会更新,并且时间会更新。我不知道这个 "backend update" 需要多少时间,我不知道在快乐的 运行 中它是否会出现在提到的标签之前,目前,从我的测试来看它从 10到 40 秒(肯定是 60 秒)。
我们有一个 Waits
class 来处理这种东西,但是我们没有验证文本更改的方法,所以我想到了这个:
private static WebDriverWait _customWait(int value) => new WebDriverWait(
clock,
Driver.Instance,
TimeSpan.FromSeconds(value),
TimeSpan.FromMilliseconds(Settings.Timeouts.SleepIntervalInMillis));
public static void WaitForTextElementToChange(Func<IWebDriver, IWebElement> elementFinder, IWebDriver driver, int time)
{
string oldValue = elementFinder.Invoke(driver).Read();
_customWait(time).Until(drv =>
{
try
{
return !elementFinder.Invoke(driver).Read().Contains(oldValue);
}
catch (NotFoundException)
{
return true;
}
catch (StaleElementReferenceException)
{
return true;
}
});
}
这行得通。我评论它是因为我还没有完全理解 Until
方法背后的语法和逻辑,我知道它给出了 WebDriverTimeoutException
并且我把它留在那里作为框架的附加方法.
因此,如果值发生变化,它会退出并保持 运行ning 可爱,但在这种特殊情况下,如果它没有变化,我不需要它来抛出异常,所以我调用了它在 try/catch
.
内
Waits.WaitForProcessToFinish(drv => processCompleteLabel); //<- context code
try
{
//If value changes before 60 secs everything is fine
Waits.WaitForTextElementToChange(drv => timeElement, someDriverObject, 60);
//60 is a hardcoded int value just for testing
}
catch (WebDriverTimeoutException)
{
//But if it doesn't change just do nothing
}
string timeElapsed = timeElement.Read(); //<- context code
我的问题是,这样可以吗?
你会怎么做?
根据我在源代码中看到的内容,我不认为 Until 的工作方式可以解决这个问题。
Until 方法在循环中执行传递给它的方法,直到返回 bool 或对象或发生超时。
public virtual TResult Until<TResult>(Func<T, TResult> condition)
{
if (condition == null)
{
throw new ArgumentNullException("condition", "condition cannot be null");
}
var resultType = typeof(TResult);
if ((resultType.IsValueType && resultType != typeof(bool)) || !typeof(object).IsAssignableFrom(resultType))
{
throw new ArgumentException("Can only wait on an object or boolean response, tried to use type: " + resultType.ToString(), "condition");
}
Exception lastException = null;
var endTime = this.clock.LaterBy(this.timeout);
while (true)
{
try
{
var result = condition(this.input);
if (resultType == typeof(bool))
{
var boolResult = result as bool?;
if (boolResult.HasValue && boolResult.Value)
{
return result;
}
}
else
{
if (result != null)
{
return result;
}
}
}
catch (Exception ex)
{
if (!this.IsIgnoredException(ex))
{
throw;
}
lastException = ex;
}
// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!this.clock.IsNowBefore(endTime))
{
string timeoutMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds", this.timeout.TotalSeconds);
if (!string.IsNullOrEmpty(this.message))
{
timeoutMessage += ": " + this.message;
}
this.ThrowTimeoutException(timeoutMessage, lastException);
}
Thread.Sleep(this.sleepInterval);
}
}
您正在做的工作有效,但我建议您在不使用 Wait.Until() 的情况下使用自己的超时循环,因为它的核心功能是在出现问题时抛出异常。
一段时间后,我正在使用 WebDriverWait
获取 WebElement
的值,但如果它没有改变,我不希望它失败,只获取当前值值并继续执行。
我正在 Web 中 运行 设置一个进程,该进程有一个 "process completed" 标签,我用它来检查它是否完成。在同一屏幕上,有一个 "elapsed time" 用于我需要阅读的过程,以报告 运行 该过程花费了多少时间。 问题是即使在 "process completed" 标签出现后,后端进程 运行ning 也会更新,并且时间会更新。我不知道这个 "backend update" 需要多少时间,我不知道在快乐的 运行 中它是否会出现在提到的标签之前,目前,从我的测试来看它从 10到 40 秒(肯定是 60 秒)。
我们有一个 Waits
class 来处理这种东西,但是我们没有验证文本更改的方法,所以我想到了这个:
private static WebDriverWait _customWait(int value) => new WebDriverWait(
clock,
Driver.Instance,
TimeSpan.FromSeconds(value),
TimeSpan.FromMilliseconds(Settings.Timeouts.SleepIntervalInMillis));
public static void WaitForTextElementToChange(Func<IWebDriver, IWebElement> elementFinder, IWebDriver driver, int time)
{
string oldValue = elementFinder.Invoke(driver).Read();
_customWait(time).Until(drv =>
{
try
{
return !elementFinder.Invoke(driver).Read().Contains(oldValue);
}
catch (NotFoundException)
{
return true;
}
catch (StaleElementReferenceException)
{
return true;
}
});
}
这行得通。我评论它是因为我还没有完全理解 Until
方法背后的语法和逻辑,我知道它给出了 WebDriverTimeoutException
并且我把它留在那里作为框架的附加方法.
因此,如果值发生变化,它会退出并保持 运行ning 可爱,但在这种特殊情况下,如果它没有变化,我不需要它来抛出异常,所以我调用了它在 try/catch
.
Waits.WaitForProcessToFinish(drv => processCompleteLabel); //<- context code
try
{
//If value changes before 60 secs everything is fine
Waits.WaitForTextElementToChange(drv => timeElement, someDriverObject, 60);
//60 is a hardcoded int value just for testing
}
catch (WebDriverTimeoutException)
{
//But if it doesn't change just do nothing
}
string timeElapsed = timeElement.Read(); //<- context code
我的问题是,这样可以吗? 你会怎么做?
根据我在源代码中看到的内容,我不认为 Until 的工作方式可以解决这个问题。
Until 方法在循环中执行传递给它的方法,直到返回 bool 或对象或发生超时。
public virtual TResult Until<TResult>(Func<T, TResult> condition)
{
if (condition == null)
{
throw new ArgumentNullException("condition", "condition cannot be null");
}
var resultType = typeof(TResult);
if ((resultType.IsValueType && resultType != typeof(bool)) || !typeof(object).IsAssignableFrom(resultType))
{
throw new ArgumentException("Can only wait on an object or boolean response, tried to use type: " + resultType.ToString(), "condition");
}
Exception lastException = null;
var endTime = this.clock.LaterBy(this.timeout);
while (true)
{
try
{
var result = condition(this.input);
if (resultType == typeof(bool))
{
var boolResult = result as bool?;
if (boolResult.HasValue && boolResult.Value)
{
return result;
}
}
else
{
if (result != null)
{
return result;
}
}
}
catch (Exception ex)
{
if (!this.IsIgnoredException(ex))
{
throw;
}
lastException = ex;
}
// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!this.clock.IsNowBefore(endTime))
{
string timeoutMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds", this.timeout.TotalSeconds);
if (!string.IsNullOrEmpty(this.message))
{
timeoutMessage += ": " + this.message;
}
this.ThrowTimeoutException(timeoutMessage, lastException);
}
Thread.Sleep(this.sleepInterval);
}
}
您正在做的工作有效,但我建议您在不使用 Wait.Until() 的情况下使用自己的超时循环,因为它的核心功能是在出现问题时抛出异常。