Selenium WebDriver PageFactory FindsBy 使用 jQuery 选择器?

Posted

技术标签:

【中文标题】Selenium WebDriver PageFactory FindsBy 使用 jQuery 选择器?【英文标题】:Selenium WebDriver PageFactory FindsBy Using jQuery Selector? 【发布时间】:2012-01-14 06:00:15 【问题描述】:

为了解释我的问题,我给出了一个小场景:

假设我有一个登录页面。

public class LoginPage

    [FindsBy(How = How.Id, Using = "SomeReallyLongIdBecauseOfAspNetControlsAndPanels_username"]
    public IWebElement UsernameField  get; set; 

    [FindsBy(How = How.Id, Using = "SomeReallyLongIdBecauseOfAspNetControlsAndPanels_password"]
    public IWebElement PasswordField  get; set; 

    [FindsBy(How = How.Id, Using = "submitButtonId")]
    public IWebElement SubmitButton  get; set; 

    private readonly IWebDriver driver;

    public LoginPage(IWebDriver driver)
    
        this.driver = driver;

        if(!driver.Url.Contains("Login.aspx"))
        
            throw new NotFoundException("This is not the login page.");
        
        PageFactory.InitElements(driver, this);
    

    public HomePage Login(Credentials cred)
    

       UsernameField.sendKeys(cred.Username);
       PasswordField.SendKeys(cred.Password);
       SubmitButton.Click();

       return new HomePage(driver);
    



[TestFixture]
public class Test : TestBase

    private IWebDriver driver;

    [SetUp]
    public void SetUp()
    

       driver = StartDriver(); // some function which returns my driver in a wrapped event or something so I can log everything it does.
    

    [Test]
    public void Test()
    
        new LoginPage(driver)
                .Login(new Credentials 
                            Username = "username", 
                             Password = "password" )
                .SomeHomePageFunction()

    

最终,我知道页面配置会发生变化,id 将基本保持不变,但我的项目正在迅速发生变化。我知道 xPath 是另一种选择,但由于页面是基于某些标准生成的,这仍然会变得很痛苦,因为路径并不总是相同。

使用上面的当前代码,页面被加载,PageFactory 通过页面构造函数初始化元素。都很棒。这是我目前使用的。

目前,如果某些东西并不总是在页面上生成,直到某个步骤。我通常会这样做:

private const string ThisIsTheUserNameFieldId = "usernamefield";

然后使用以下命令打开 webdriver:

// Navigate to login page

// code here

// Enter in credentials

driver.FindElement(By.Id(ThisIsTheUserNameFieldId)).SendKeys(cred.Username);

结构不如 PageFactory,但它肯定是我无法解决的要求。

我最近遇到了一些与 C#.Net 一起使用的 jQuery 选择器代码,它扩展了 RemoteWebDriver 的功能,我可以使用 jQuery 选择器在页面上找到我的元素。

Selenium jQuery for C#.Net (Including Source)

// So I can do things like this:
driver.FindElement(By.jQuery("a").Find(":contains('Home')").Next())

有谁知道我可以如何扩展 Selenium WebDriver 中的 [FindsBy] 属性,以便可以使用类似以下的内容(伪代码)?

[FindsBy(How = How.jQuery, Using = "div[id$='txtUserName']")]
public IWebElement UsernameField  get; set; 

【问题讨论】:

请记住,XPath 非常强大,您可以轻松地将 div[id$='txtUserName'] 转换为 //div[ends-with(@id, 'txtUserName')] 我可以发誓我曾尝试过这种方法。我做了一个快速的单元测试。 OpenQA.Selenium.InvalidSelectorException:给定的选择器 //input[ends-with(@id, 'txtUserName')] 无效或不会生成 WebElement。发生以下错误:[InvalidSelectorError] 无法找到具有 xpath 表达式的元素 //input[ends-with(@id, 'txtUserName')] 因为以下错误:[Exception..."The expression is not a法律表达。”代码:“51”nsresult:“0x805b0033(NS_ERROR_DOM_INVALID_EXPRESSION_ERR)”位置:“resource://fxdriver/modules/atoms.js 行:2394”] 很遗憾,因为我在几个页面上有几个重要的网络元素,这些元素在网站使用所涉及的每个步骤的每个过程中都被大量使用。我还尝试使用 Firefox 插件来帮助识别 xPath 表达式,甚至那些似乎被 Selenium 无效的表达式。但是我确实认为该插件已经很老了,但它仍然存在。在它工作之前它很混乱,这很好,但是我似乎总是陷入 XPath 的这个问题。 真可惜,我本来希望 WebDriver 能够处理 XPath 函数...我想您需要像我在下面发布的那样。 原来它是 xPath 2 的一部分,新的 Selenium 2 WebDriver 甚至都不支持它......这太糟糕了。 【参考方案1】:

这不扩展 [FindsBy],但你知道你可以使用 javascript 返回的元素吗?:

var driver = new FirefoxDriver  Url = "http://www.google.com" ;
var element = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.getElementsByName('q')[0];");
element.SendKeys("hello world");

您可以通过首先注入 jquery(取自 JQuerify 并修改)轻松扩展它以允许 jquery 选择器:

const string js =
     @"var b=document.getElementsByTagName('body')[0]; if(typeof jQuery=='undefined')var script=document" +
     @".createElement('script'); script.src='http://code.jquery.com/jquery-latest.min.js';var head=document" +
     @".getElementsByTagName('head')[0],done=false;script.onload=script.onreadystatechange=function()if(!" +
     @"done&&(!this.readyState||this.readyState=='loaded'||this.readyState=='complete'))done=true;script." +
     @"onload=script.onreadystatechange=null;head.removeChild(script);;head.appendChild(script);";
((IJavaScriptExecutor)driver).ExecuteScript(js);

然后运行javascript来选择你想要的元素:

var driver = new FirefoxDriver  Url = "http://www.google.com" ;
var element = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(@"return $('input[name*=""q""]')[0];");
element.SendKeys("hello world");

【讨论】:

我希望我能采用这种方法,我真的这样做了。我与 ASP.Net 打交道,一旦进行了一些设置更改,大多数 id 都会更改。如果可以的话,我会尝试使用 xPath 分辨率,因为所有这些 jQuery 添加和 javascript 执行对于在开发阶段快速移动的项目来说维护和处理都太多了。 太糟糕了...我想您可以提交功能请求以升级到 XPath 2.0,或者允许使用 JQuery 选择器。 这可能适合您,也可能不适合您,但您可以获取 Webinator 项目:webinator.codeplex.com。这是一个 pre-alpha 项目(尽管 WebDriver 部分功能齐全),我很乐意为其添加 JQuery 支持。 我想这将不得不这样做:) 仅供参考,这个答案准确地描述了 OP 发布的文章确实

以上是关于Selenium WebDriver PageFactory FindsBy 使用 jQuery 选择器?的主要内容,如果未能解决你的问题,请参考以下文章

Selenium Webdriver概述

appium的webdriver和selenium有啥区别?

selenium之python源码解读-webdriver继承关系

From  selenium  import  webdriver

Selenium WebDriver(Python)API

selenium+python - webdriver​模拟键盘ENTER没有效果