我遵循Selenium建议的Page Object模式,但我如何为页面创建更专业的WebElement。具体来说,我们的页面上有表,我编写了一些帮助函数来获取表的特定行、返回表的内容等。
目前,以下是我创建的一个页面对象的片段,其中包含一个表:
public class PermissionsPage {
@FindBy(id = "studyPermissionsTable")
private WebElement permissionTable;
@FindBy(id = "studyPermissionAddPermission")
private WebElement addPermissionButton;
...
}
所以,我想做的是让permissionsTable成为一个更定制的WebElement,它具有我前面提到的一些方法。
例如:
public class TableWebElement extends WebElement {
WebElement table;
// a WebDriver needs to come into play here too I think
public List<Map<String, String>> getTableData() {
// code to do this
}
public int getTableSize() {
// code to do this
}
public WebElement getElementFromTable(String id) {
// code to do this
}
}
我希望我所要解释的有道理。我想我要寻找的是一种让这个自定义WebElement做一些特定于表的其他事情的方法。将此自定义元素添加到页面,并利用Selenium基于注释将webelements连接到页面的方式。
有可能吗?如果是这样的话,有人知道如何做到这一点吗?
作为后续,这就是我最终所做的(以防其他人有同样的问题)。下面是我作为WebElement的包装器创建的类的片段:
public class CustomTable {
private WebDriver driver;
private WebElement tableWebElement;
public CustomTable(WebElement table, WebDriver driver) {
this.driver = driver;
tableWebElement = table;
}
public WebElement getTableWebElement() {
return tableWebElement;
}
public List<WebElement> getTableRows() {
String id = tableWebElement.getAttribute("id");
return driver.findElements(By.xpath("//*[@id='" + id + "']/tbody/tr"));
}
public List<WebElement> getTableHeader() {
String id = tableWebElement.getAttribute("id");
return tableWebElement.findElements(By.xpath("//*[@id='" + id + "']/thead/tr/th"));
}
.... more utility functions here
}
然后我在任何通过引用创建的页面中使用它,如下所示:
public class TestPage {
@FindBy(id = "testTable")
private WebElement myTestTable;
/**
* @return the myTestTable
*/
public CustomTable getBrowserTable() {
return new CustomTable(myTestTable, getDriver());
}
我唯一不喜欢的是,当页面想要获取表时,它会创建一个“新”表。我这样做是为了避免在更新表中的数据(即单元格更新、行添加、行删除)时发生StaleReferenceException。如果有人对我如何避免每次请求时都创建一个新实例有任何建议,而是返回更新后的WebElement,那就太好了!
您可以使用WebDriver扩展框架创建自定义WebElement,该框架提供了一个WebComponent类,该类实现WebElement接口
创建您的自定义WebElement
public class Table extends WebComponent {
@FindBy(tagName = "tr")
List<Row> rows;
public Row getRow(int row) {
return rows.get(row - 1);
}
public int getTableSize() {
return rows.size();
}
public static class Row extends WebComponent {
@FindBy(tagName = "td")
List<WebElement> columns;
public WebElement getCell(int column) {
return columns.get(column - 1);
}
}
}
...然后使用@FindBy注释将其添加到您的PageObject中,并在调用PageFactory.initElements方法时使用WebDriverExtensionFieldDecorator
public class PermissionPage {
public PermissionPage(WebDriver driver) {
PageFactory.initElements(new WebDriverExtensionFieldDecorator(driver), this);
}
@FindBy(id = "studyPermissionsTable")
public Table permissionTable;
@FindBy(id = "studyPermissionAddPermission")
public WebElement addPermissionButton;
}
。。。然后在测试中使用它
public class PermissionPageTest {
@Test
public void exampleTest() {
WebDriver driver = new FirefoxDriver();
PermissionPage permissionPage = new PermissionPage(driver);
driver.get("http://www.url-to-permission-page.com");
assertEquals(25, permissionPage.permissionTable.getTableSize());
assertEquals("READ", permissionPage.permissionTable.getRow(2).getCell(1).getText());
assertEquals("WRITE", permissionPage.permissionTable.getRow(2).getCell(2).getText());
assertEquals("EXECUTE", permissionPage.permissionTable.getRow(2).getCell(3).getText());
}
}
或者更好地使用WebDriver Extensions PageObject实现
public class PermissionPage extends WebPage {
@FindBy(id = "studyPermissionsTable")
public Table permissionTable;
@FindBy(id = "studyPermissionAddPermission")
public WebElement addPermissionButton;
@Override
public void open(Object... arguments) {
open("http://www.url-to-permission-page.com");
assertIsOpen();
}
@Override
public void assertIsOpen(Object... arguments) throws AssertionError {
assertIsDisabled(permissionTable);
assertIsDisabled(addPermissionButton);
}
}
以及具有WebElements静态断言方法的JUnitRunner
import static com.github.webdriverextensions.Bot.*;
@RunWith(WebDriverRunner.class)
public class PermissionPageTest {
PermissionPage permissionPage;
@Test
@Firefox
public void exampleTest() {
open(permissionPage);
assertSizeEquals(25, permissionPage.permissionTable.rows);
assertTextEquals("READ", permissionPage.permissionTable.getRow(2).getCell(1));
assertTextEquals("WRITE", permissionPage.permissionTable.getRow(2).getCell(2));
assertTextEquals("EXECUTE", permissionPage.permissionTable.getRow(2).getCell(3));
}
}
我创建了一个结合了所有WebDriver界面的界面:
public interface Element extends WebElement, WrapsElement, Locatable {}
它只是用来包装WebElements在包装元素时可以做的所有事情。
然后是实现:
public class ElementImpl implements Element {
private final WebElement element;
public ElementImpl(final WebElement element) {
this.element = element;
}
@Override
public void click() {
element.click();
}
@Override
public void sendKeys(CharSequence... keysToSend) {
element.sendKeys(keysToSend);
}
// And so on, delegates all the way down...
}
然后,例如复选框:
public class CheckBox extends ElementImpl {
public CheckBox(WebElement element) {
super(element);
}
public void toggle() {
getWrappedElement().click();
}
public void check() {
if (!isChecked()) {
toggle();
}
}
public void uncheck() {
if (isChecked()) {
toggle();
}
}
public boolean isChecked() {
return getWrappedElement().isSelected();
}
}
在我的脚本中使用它时:
CheckBox cb = new CheckBox(element);
cb.uncheck();
我还提出了一种包装元素类的方法。您必须创建一些工厂来替换内置的PageFactory,但这是可行的,并且提供了很大的灵活性。
我在我的网站上记录了这个过程:
我还有一个名为selophane的项目,它的灵感来自于这个问题和其他问题:selophane
扩展是专门设计的在 Yii 应用中随时可拿来使用的, 并可重发布的软件包。例如, yiisoft/yii2-debug 扩展在你的应用的每个页面底部添加一个方便用于调试的工具栏, 帮助你简单地抓取页面生成的情况。 你可以使用扩展来加速你的开发过程。 信息: 本文中我们使用的术语 "扩展" 特指 Yii 软件包。而用术语 "软件包" 和 "库" 指代非 Yii 专用的通常意义上的软件包。 使用扩展
vscode-react-native vscode-go
扩展为现有的类、结构体、枚举类型、或协议添加了新功能。这也包括了为无访问权限的源代码扩展类型的能力(即所谓的逆向建模)。扩展和 Objective-C 中的分类类似。(与 Objective-C 的分类不同的是,Swift 的扩展没有名字。) Swift 中的扩展可以: 添加计算实例属性和计算类型属性; 定义实例方法和类型方法; 提供新初始化器; 定义下标; 定义和使用新内嵌类型; 使现有的类型遵
概述 范例-hello-world 范例-word-count 范例-language-server 范例-调试器 调试-扩展 安装-扩展 范式-原则 测试-扩展 用我们的方法创造扩展
本页包含内容: 扩展语法 计算型属性 构造器 方法 下标 嵌套类型 扩展就是向一个已有的类、结构体或枚举类型添加新功能(functionality)。这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模)。扩展和 Objective-C 中的分类(categories)类似。(不过与Objective-C不同的是,Swift 的扩展没有名字。) Swift 中的扩展可以: 添加计算型属
Jinja2 支持扩展来添加过滤器、测试、全局变量或者甚至是处理器。扩展的主要动力是 把诸如添加国际化支持的常用代码迁移到一个可重用的类。 添加扩展 扩展在 Jinja2 环境创建时被添加。一旦环境被创建,就不能添加额外的扩展。要添加 一个扩展,传递一个扩展类或导入路径的列表到 Environment 构造函数的 environment 参数。下面的例子创建了一个加载了 i18n 扩展的 Jinj
一、本功能块说明 1.功能块简介 本功能块主要集中了全站各个模块的一些扩展属性,能够更加直观快速的进入所需的功能页面! 二、术语约定 1.导航栏 在本功能块下 导航栏 统一指整站的头部导航,既如下图所示: 2.菜单栏 在本功能块下 菜单栏 统一指扩展导航栏下的左侧菜单,既如下图所示:
http2协议强制规定了接收方必须读取并忽略掉所有未知帧(即未知帧类型的帧)。双方可以在逐跳原则(hop-by-hop basis)基础上协商使用新的帧,但这些帧的状态无法被改变,也不受流控制。 是否应该允许添加扩展的这个话题在制定http2协议的时候被反复讨论了很久,但在draft-12之后,最终尘埃落定确定了允许添加扩展。 但扩展不再是协议本身的一部分,它被记录在核心协议规范之外。现在已经有两