2012-07-25 121 views
10

我遵循Selenium建議的頁面對象模式,但是如何爲頁面創建更專用的WebElement。具體來說,我們在我們的頁面上有表格,並且我寫了一些幫助函數來獲取表格的特定行,返回表格的內容等。擴展Selenium WebDriver 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基於註釋將Web元素連接到頁面的方式。

可能嗎?如果是這樣,有人知道這可以做到嗎?

回答

20

我創建了一個結合了所有接口的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(); 

我也拿出用一種包裝Element類的方法。您必須創建幾個工廠來替換內置的PageFactory,但它是可行的,並且它具有很大的靈活性。

我已經證明這個過程在我的網站上:

我也有一個項目叫做selophane,是由這個問題和其他問題的啓發: selophane

+0

這就是我也是這麼做的,但有點不同..我創建了一個抽象類,它實現了一個擴展WebElement接口的自定義接口。加載抽象中的所有方法並在最終的類中添加方法。並且在我的InvocationHandler中,如果它們在webelement的接口中聲明,我攔截該方法並將其重定向到webelement對象的方法;否則,我用自定義webelement包裝器包裝元素;並調用該方法。 PS。 +1爲博客:)謝謝! – rrw 2016-03-28 04:01:18

0

何必延長WebElement?你是否試圖開發Selenium包?那麼如果你是這樣的話,那麼擴展這種方法是沒有意義的,除非你的增加可以適用於你使用的每一個網頁元素,而不僅僅是那些對你的表格特定的元素。

爲什麼不做這樣的事情:

public class PermissionsPage extends TableWebElement{ 

...permissions stuff... 

} 

import WebElement 

public class TableWebElement{ 

...custom web elements pertaining to my page... 

} 

我不知道這是否回答你的問題,但在我看來,這是一個多級的建築問題比什麼都重要。

0

我會創造我所說的「SubPageObject」代表在PageObject一個PageObject ...

的好處是,你可以爲它定製的方法,你可以初始化只有你真正需要的內WebElements這個SubPageObject。

1

旁註:WebElement不類,其接口,這意味着你的類看起來更像是這樣的:

public class TableWebElement implements WebElement { 

但在這種情況下,你必須實現這是所有方法的webdriver。而且它有點矯枉過正。

這裏是這樣,我怎麼做到這一點 - 所建議的硒和有我自己的類「重新發明了車輪」我得到了徹底擺脫提出PageObjects的。我對整個應用程序只有一個類:

public class WebUI{ 
    private WebDriver driver;  
    private WebElement permissionTable; 

    public WebUI(){ 
     driver = new firefoxDriver(); 
    } 

    public WebDriver getDriver(){ 
    return driver; 
    } 

    public WebElement getPermissionTable(){ 
    return permissionTable; 
    } 

    public TableWebElement getTable(){ 
    permissionTable = driver.findElement(By.id("studyPermissionsTable")); 
    return new TableWebElement(this); 
    } 
} 

然後,我有我的助手類

public class TableWebElement{ 
    private WebUI webUI; 

public TableWebElement(WebUI wUI){ 
    this.webUI = wUI; 
} 

public int getTableSize() { 
    // because I dont know exactly what are you trying to achieve just few hints 
    // this is how you get to the WebDriver: 
    WebElement element = webUI.getDriver().findElement(By.id("foo")); 

    //this is how you get to already found table: 
    WebElement myTable = webUI.getPermissionTable(); 

} 

} 

樣品測試:

@Test 
public void testTableSize(){ 
    WebUI web = new WebUI(); 
    TableWebElement myTable = web.getTable(); 
    Assert.assertEquals(myTable.getSize(), 25); 
} 
+0

我喜歡這個主意,我「會嘗試一下,讓你知道如何去。 – pipplupp 2012-07-26 16:45:44

+0

btw,我不知道誰指出這個答案沒有用。我很好奇爲什麼有人以這種方式投票。 – pipplupp 2012-07-26 19:16:36

+0

至少你喜歡這個想法:) – 2012-07-27 09:48:03

0

何不做一個網頁元素的包裝?喜歡這個?

class WEBElment 
{ 

public IWebElement Element; 

public WEBElement(/*send whatever you decide, a webelement, a by element, a locator whatever*/) 

{ 

Element = /*make the element from what you sent your self*/ 

} 


public bool IsDisplayed() 

{ 

return Element.Displayed; 

} 

} // end of class here 

但你可以讓你的課程比這更復雜。只是一個概念

1

作爲跟進,這是我最終做的(以防其他人有這個相同的問題)。下面是我作爲一個包裝的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()); 
} 

唯一令我不喜歡當頁面想要獲取表格時,它會創建一個「新」表格。我這樣做是爲了避免在表中的數據更新時發生StaleReferenceExeptions(即單元更新,添加行,刪除行)。如果任何人有任何建議,我可以避免每次請求時創建一個新的實例,而是返回更新的WebElement,這將是偉大的!

2

您可以使用WebDriver Extensions框架創建自定義WebElements,該框架提供了We調用PageFactory.initElements方法時,它實現了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並使用WebDriverExtensionFieldDecorator bComponent類

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); 
    } 
} 

,並與靜態JUnitRunner斷言爲WebElements

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)); 
    } 
} 
方法
+0

我在2年前發佈了這個問題,我發現自己正在重新訪問這個相同的場景。我忘了我甚至問過這個問題。我正在看各種答案,你的webdriverextensions看起來很棒!填充硒葉打開的孔。我將閱讀你的文檔,並給它一個去。 – pipplupp 2015-06-24 23:28:13

0

拿一個lo確定在htmlelements框架,它看起來正是你所需要的。它已經預先實現了複選框,單選框,表格,表單等常用元素,您可以輕鬆創建自己的元素並將其中一個元素插入到其他元素中,從而創建清晰的樹狀結構。

0

步驟1)創建名爲Element基類,它擴展了IWrapsElement接口

public class Element : IWrapsElement 
{ 
    public IWebElement WrappedElement { get; set; } 
    public Element(IWebElement element) 
    { 
     this.WrappedElement = element; 
    } 
} 

步驟2)用於每個定製元素創建一個類,然後從Element

public class Checkbox : Element 
{ 
    public Checkbox(IWebElement element) : base(element) { } 

    public void Check(bool expected) 
    { 
     if (this.IsChecked()!= expected) 
     { 
      this.WrappedElement.Click(); 
     } 
    } 

    public bool IsChecked() 
    { 
     return this.WrappedElement.GetAttribute("checked") == "true"; 
    } 
} 

用法繼承:

a)

Checkbox x = new Checkbox(driver.FindElement(By.Id("xyz"))); 
x.Check(true) 

B)

private IWebElement _chkMale{ get; set; } 
[FindsBy(How = How.Name, Using = "chkMale")] 

private Checkbox ChkMale 
    { 
     get { return new Checkbox (_chkMale); } 
    } 
ChkMale.Check(true); 
相關問題