在多个页面上具有相同By定位符的元素的问题
本文关键字:By 定位 元素 问题 | 更新日期: 2023-09-27 18:17:03
我有5页(A, B, C, D, E). A, B, C和D每个包含一个按钮Id 'Next'将加载下一页。现在,问题是,有时(不是总是),"下一步"按钮不点击每个页面。
我的代码应该做以下事情:我们启动浏览器并通过URL导航到页面A。然后,我们在页面上执行一些逻辑,然后单击"下一步"按钮。我们到达页面B,在页面上执行一些逻辑,然后单击"下一步"按钮。我们到达C页,立即点击"下一步"按钮,没有做任何其他事情。在D页,我们执行一些逻辑并单击"Next"按钮。(以此类推…)
现在,问题是,在C页,"下一步"按钮并不总是点击,但它不会抛出FindElement错误。所以它试图在D页执行逻辑,而web驱动程序崩溃,因为它仍然在c页上。我怎么能解决这个问题?请注意,我确实使用动态webdriver等待元素出现在页面上,但这使得如此不同,因为相同的定位器它总是相同的(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();这解决了我的问题,但这是一个代码气味,我想避免它
你有两个选择:
-
确保页面已加载并且您在该页面
您可以为页面的唯一元素添加wait.Until()
。 -
获取基于父页面的按钮选择器
由于您在每个页面对象中都有Continue()
,因此您可以使用css选择器来根据父页面或基于页面中不存在的唯一部分来识别按钮,否则在每个页面中使用相同选择器的相同方法有什么意义?您可以通过使用FireBug轻松地找到它。只需导航到页面,右键单击该元素,单击FireBug检查元素,然后右键单击该元素并单击"复制CSS路径"。
:
假设有一个div
和id='pageC'
。
你可以使用像#pageC #Next
您的代码对于您要完成的任务来说过于复杂了。
首先得到你的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"));
}
我猜您的脚本运行得足够快,在第3页有机会加载之前,它在第2页上第二次单击Next按钮。解决这个问题的一种方法是等待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 Objects,否则似乎没有理由要从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();