在多个页面上具有相同按位置的元素的问题

时间:2016-11-09 15:25:46

标签: c# selenium

我有5页(A,B,C,D,E)。 A,B,C和D每个都包含一个带有Id' Next'这将加载下一页。现在,问题在于,有时(并非总是),' Next'每页都没有点击按钮。

我的代码应该执行以下操作:我们启动浏览器并通过URL导航到页面A.然后,我们在页面上执行一些逻辑,然后单击“下一步”按钮。按钮。我们到达页面B并在页面上执行一些逻辑,然后单击“下一步”。按钮。我们到达页面C,然后立即点击“下一步”'按钮没有做任何其他事情。在第D页,我们执行一些逻辑并点击“下一步”按钮。按钮。 (依此类推......)

现在,问题是在第C页上,'下一步'按钮并不总是被单击,但它不会为FindElement抛出错误。因此它尝试在页面D上执行逻辑并且Web驱动程序崩溃,因为它仍然在页面C上。如何解决此问题?请注意,我确实使用动态webdriverWait来显示页面上存在的元素,但这会产生差异,因为定位器始终相同(ID =' Next')。另外,请注意我不会返回我的PageObjects - 我不确定这是否是绝对必要的。

有什么想法吗?

这是我的代码:

   public class Page
    {      
        public Page()
        {
            PageFactory.InitElements(SeleniumTests.driver, this);
        }       
    }

public static class SeleniumTests
    {
        public static IWebDriver driver { get; set; }
    }

 class Page_1 : Page
    {       
        [FindsBy(How = How.Id, Using = "Next")]
        public void Continue()
        {
            btnNext.SafeClick();
        }
    }

class Page_2 : Page
        {       
            [FindsBy(How = How.Id, Using = "Next")]
            public void Continue()
            {
                btnNext.SafeClick();
            }
        }

class Page_3 : Page
        {       
            [FindsBy(How = How.Id, Using = "Next")]
            public void Continue()
            {
                btnNext.SafeClick();
            }
        }
  class Page_4 : Page
            {       
                [FindsBy(How = How.Id, Using = "Next")]
                public void Continue()
                {
                    btnNext.SafeClick();
                }
            }
  class Page_5 : Page
            {       
                [FindsBy(How = How.Id, Using = "Next")]
                public void Continue()
                {
                    btnNext.SafeClick();
                }
            }

   public static class SeleniumExtensionMethod
    { 
        public static WebDriverWait wait = new WebDriverWait(SeleniumTests.driver, TimeSpan.FromSeconds(15));
        public static void SafeClick(this IWebElement webElement, Double seconds = 15)
            {
                try
                {
                    wait.Until(ExpectedConditions.ElementToBeClickable(webElement)).Click();
                }
                catch (System.Reflection.TargetInvocationException ex)
                {
                    Console.WriteLine(ex.InnerException);
                }
            }
    }

最后:

 public partial class Form1 : Form
    {
        Page_1 pageA = new Page_1();
        pageA.PerformSomeLogic();
        pageA.Continue();

        Page_2 pageB = new Page_2();
        pageB.PerformSomeLogic();
        pageB.Continue();

        Page_3 pageC = new Page_3();
        // Don't do anything here, just continue.
        pageC.Continue();


        Page_4 pageD = new Page_4();
        pageD.PerformSomeLogic();// -----> here is crashes, as the previous line 'pageC.Continue()' was not really executed, it seems as though the button was clicked 2 times on page B
        pageD.Continue() ;          


        Page_5 pageE = new Page_5();
        pageD.PerformSomeLogic();
        pageE.Continue();   
}

编辑:我想要的,理想情况下是做某种动态等待,在这种情况下实际上会起作用。我也可以使用Thread.Sleep();这解决了我的问题,但这是代码味道,我想避免它。

3 个答案:

答案 0 :(得分:1)

您有两个选择:

  1. 确保页面已加载并且您在该页面上 您可以为页面的唯一元素添加wait.Until()

  2. 根据父页面获取按钮的选择器
    由于您在每个页面对象中都有Continue(),因此您可以使用css选择器根据父页面或基于页面中不存在于其他页面中的唯一部分来标识按钮,否则有什么意义呢?在每个页面中使用相同的选择器具有相同的方法。您可以使用FireBug轻松找到它。只需导航到该页面,右键单击该元素,单击使用FireBug检查元素,然后右键单击该元素并单击“复制CSS路径”。

  3. 例如:
    假设您有一个div id='pageC' 你可以使用像#pageC #Next

    这样的css选择器

答案 1 :(得分:1)

您尝试完成的任务的代码过于复杂。

首先获取IWebDriver

IWebDriver driver = new FirefoxDriver();

在这种情况下你应该使用隐式等待,让我们从设置为15秒的超时开始。这将确保driver.FindElements()次呼叫在超时前搜索15秒。如果在15秒之前找到该元素,它将在那一刻停止等待。

driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));

由于您的下一个按钮在每个页面上都有相同的id,我们可以使用By.Id("Next")查找每个页面上的下一个按钮。

driver.FindElement(By.Id("Next"));

全部放在一起:

IWebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
for(int page = 1; page < 5; page++) //Iterate through all pages, click next when applicable
{
    driver.FindElement(By.Id("Next"));
}

IWebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
if(driver.FindElement(By.Id("Next")).Enabled) //Ensure button is clickable before proceeding
{
    driver.FindElement(By.Id("Next"));
}

答案 2 :(得分:1)

我的猜测是你的脚本运行得足够快,以至于在第2页有机加载之前第二次点击了Next按钮。解决此问题的一种方法是等待“下一步”按钮过时。基本逻辑是

1. Click the Next button
2. Wait for the Next button to be stale

代码可能类似于

public void Continue()
{
    btnNext.SafeClick();
    btnNext.WaitForStale();
}

其中.WaitForStale()只是

wait.until(ExpectedConditions.stalenessOf(btnNext));

此外,除非您确实简化了自己的页面对象,否则似乎没有理由让Page_1到Page_5。如果它们都具有相同的功能,则它们应该位于单个页面中,并且每次移动到下一页时都会重新实例化页面,例如

public partial class Form1 : Form
{
    Page_1 pageA = new Page_1();
    pageA.PerformSomeLogic();
    pageA.Continue();

    pageB = new Page_1(); <-- this can be Page_1() or better yet, renamed to ContentPage or something that better represents the type of page rather than the page number.
    pageB.PerformSomeLogic();
    pageB.Continue();