【问题标题】:Using WebDriverWait to wait if value changes after some time如果值在一段时间后发生变化,则使用 WebDriverWait 等待
【发布时间】:2019-09-09 20:54:31
【问题描述】:

一段时间后,我使用WebDriverWait 获取WebElement 的值,但如果它没有改变,我不希望它失败,只需获取当前值并继续使用执行。

我正在 Web 中运行一个进程,该进程有一个“进程已完成”标签,我用它来检查它是否已完成。在同一屏幕上,我需要阅读该进程的“经过时间”,以报告运行该进程所需的时间。 问题是,即使出现“进程完成”标签,后端进程仍在运行,并且时间得到更新。我不知道这个“后端更新”需要多长时间,我不知道在快乐运行中它是否会出现在提到的标签之前,目前,从我的测试来看,它从 10 秒到 40 秒(60 到确定)。

我们有一个Waits 类来处理这类东西,但是我们没有这个文本更改验证的方法,所以我想出了这个:

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,我将其留作框架的附加方法。

所以,如果值发生变化,它就会出来并继续运行,但在这种特殊情况下,如果它没有变化,我不需要它来抛出那个异常,所以我在 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

我的问题是,这样可以吗? 你会怎么做?

【问题讨论】:

  • StaleElement 如果元素发生变化应该被抛出,所以你可以在原始元素上检查它并在它被抛出后确认预期的文本。
  • 我一直在玩一些代码,尽管元素改变了它的值,但它并没有抛出那个异常。这是 html 代码,在检查模式下查看它时,divTime Elapsed : ##:## 文本闪烁并且值得到更新。我猜是正常行为。 &lt;div class="time-elapsed-heading"&gt;Time Elapsed : 00:10&lt;/div&gt; 但我看不出我应该在哪里做出改变来尝试你的想法。能给我一个提示吗?
  • 不太确定,但 element.getText() 似乎如果“时间已过”文本已更新,它会抛出陈旧的元素。在进程完成标签出现后尝试获取元素,然后休眠 60 秒。尝试从同一元素中获取文本,然后查看是否引发异常。如果是这样,它已被更新。 (显然最好在服务器端放置一个断言......如果标签在后端进程仍在运行时更新,则断言)

标签: c# selenium webdriverwait


【解决方案1】:

根据我在源代码中看到的内容,我认为Until 的工作方式无法解决这个问题。

Until 方法在循环中执行传递给它的方法,直到返回布尔值或对象或发生超时。

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() 的情况下使用自己的超时循环,因为它的核心功能是在出现问题时抛出异常。

【讨论】:

  • 所以我通过阅读本文假设答案是“不要这样做并制作自己的自定义方法”,这听起来对我来说是正确的,但我希望不必诚实地这样做。无论如何,我将不得不再玩一点Until。谢谢!
猜你喜欢
  • 2019-10-07
  • 1970-01-01
  • 2012-09-26
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多