【问题标题】:How to add the single wait for two different element in Selenium [C#]如何在 Selenium [C#] 中添加单个等待两个不同元素
【发布时间】:2019-02-19 13:51:31
【问题描述】:

我的应用程序中有两个不同的表单,表单输入数据加载可以使用 UI 中可用的预定义模板完成(即输入文本字段值将根据模板选择预先填充)。当数据加载发生时,元素渲染不会发生,只会填充输入字段值。为了确认数据加载,我使用如下等待

var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(60));

wait.Until(x => x.FindElement(By.XPath(Element1_FieldXPath)).GetAttribute("value").Length > 1);

在任何时候,Form1 或 Form2 都是可见的。因此,我需要确认 Form1 或 Form2 中的数据加载。所以,我需要编写一个通用方法来处理这种情况,我遇到了以下解决方案,

public bool IsDataLoadingCompleted()
{
   var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(60));

   try
   {
       wait.Until(x => x.FindElement(By.XPath(Form1_FieldXPath)).GetAttribute("value").Length > 1);
       return true;
   }
   catch (TimeoutException)
   {
       try
       {
           wait.Until(x => x.FindElement(By.XPath(Form2_FieldXPath)).GetAttribute("value").Length > 1);
           return true;
       }
       catch (TimeoutException)
       {
           return false;
       }
   }      
}

在我的解决方案中,当 form2 在 UI 中可见时,最坏情况的等待时间是 120s。我需要用单等待而不是双等待来解决上述问题。

有没有其他方法可以用最少的等待时间解决问题?

示例 HTML:

Form1 - Field1 HTML:

<div class="form-group field field-string">
    <label class="control-label" for="root_employeeName">Employee name</label>
    <input class="form-control" id="root_employeeName" label="Employee name" placeholder="" type="text" value="">
</div>

Form2 - Field1 HTML:

<div class="form-group field field-string">
    <label class="control-label" for="root_employeeAddress">Employee Address</label>
    <input class="form-control" id="root_employeeAddress" label="Employee Address" placeholder="" type="text" value="">
</div>

【问题讨论】:

  • 答案取决于这些表格的定位器。你能分享表单的html代码吗?
  • @theGuy:问题中添加了示例 HTML

标签: c# selenium selenium-webdriver css-selectors webdriverwait


【解决方案1】:

我假设总是显示一个表单并且定位器有一个静态的id

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
wait.Until(ExpectedConditions.ElementExists(By.CssSelector("input[class='form-control']")))
string elementid = FindElement(By.CssSelector("input[class='form-control']")).GetAttribute("id") // or GetAttribute("label") 
if(elementid=="root_employeeName"){
 // do your action here if name form is displayed
}
else if(elementid=="root_employeeAddress"){
// do you action here if Address form is displayed
}

【讨论】:

    【解决方案2】:

    您可以通过使用并行运行的任务来解决这个问题。所需的代码如下所示,Task.WaitAny 可以解决问题。

    public static bool WaitUntilOneFormLoaded(IWebDriver driver)
    {
        var task1 = IsFormLoadedAsync(driver, "//some/xpath1");
        var task2 = IsFormLoadedAsync(driver, "//some/xpath2");
        Task.WaitAny(task1, task2);
        var completedTask = Task.WaitAny(task1, task2);
        switch (completedTask)
        {
            case 0: return task1.Result;
            case 1: return task2.Result;
            default: return false; // Timeout
        }
    }
    
    public static Task<bool> IsFormLoadedAsync(IWebDriver driver, string xpath)
    {
        return Task.Run(() =>
        {
            try
            {
                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
                wait.Until(x => driver.FindElement(By.XPath(xpath)).GetAttribute("value").Length > 1);
                return true;
            }
            catch (TimeoutException)
            {
                return false;
            }
        });
    }
    

    【讨论】:

    • 这仅在超时时间相等时有效(在本例中为 60 秒)。想象一下当一个超时设置为 30 秒而另一个超时设置为 60 时会发生什么。
    【解决方案3】:

    您可以逗号分隔 CssSelectors 来构造OR 逻辑,您可以使用以下任一解决方案:

    • CSS_SELECTOR A:

      new WebDriverWait(_driver, TimeSpan.FromSeconds(120)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector('#root_employeeName, #root_employeeAddress')));
      
    • CSS_SELECTOR B:

      new WebDriverWait(_driver, TimeSpan.FromSeconds(120)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("label[for='root_employeeName'], label[for='root_employeeAddress']")));
      
    • 你可以在Groups of selectors找到参考

    工作代码:

    public bool IsDataLoadingCompleted(){
    
        var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(60));
        try
        {
            wait.Until(x => x.FindElement(By.CssSelector("[label='Form1_Field'],[label='Form1_Field']")).GetAttribute("value").Length > 1);
            return true;
        }
        catch (TimeoutException)
        {
            return false;
        }
    }
    

    【讨论】:

    • 那将是一个不错的解决方案。仅适用于 css 选择器,或者也适用于 xpath、className 和 linkText?
    • 以上建议是为我制定的。我已经用工作代码编辑了答案
    猜你喜欢
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 2019-05-31
    • 2020-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多