0

I am describing a grid or table view using Selenium. What I want to do is to develop an abstract class Table from which another classes will inherit. Here is the idea:

AbstractTable class:

public abstract class AbstractTable extends HtmlElement {
    public abstract Class<? extends AbstractRow> getHeader();
    public abstract Class<? extends AbstractRow> getRow();

    private Class<? extends AbstractRow> tableHeader = getHeader();
    private Class<? extends AbstractRow> tableRow = getRow();

    public AbstractTable() { // init method }
}

AbstractRow class:

@FindBy(xpath = ".//thead/tr")
public abstract class AbstractRow extends HtmlElement {

    @Override
    public Rectange getRect() { return null; }
}

MyTable class:

class MyTable extends AbstractTable {

    @Override
    public Class<? extends AbstractRow> getHeader() { return TableHead.class; }
    @Override
    public Class<? extends AbstractRow> getRow() { return TableRow.class; }

    @FindBy(xpath = ".//thead/tr")
    public static class TableHead extends AbstractRow { // some fields }

    @FindBy(xpath = ".//tbody/tr[not(@class = 'clicked')]")
    public static class TableRow extends AbstractRow { // some fields }
}

Imagine that there are more than one class which is similar to MyTable.

So, my main question is: will my inner classes of class MyTable be decorated and initialized? Or, if not, then maybe there is a way to do this more efficient?

K. Khanda
  • 550
  • 4
  • 11
  • 1
    Note: initializing private fields from abstract methods is a really bad idea. It's precisely the same as invoking overridable methods from the constructor (because that's actually what you're doing). Instead, inject instances of `Class extends AbstractRow>` (or instances of `AbstractRow`) as constructor parameters. – Andy Turner Apr 06 '17 at 15:04
  • Okay, I'll take this as a note. Maybe you can advice me a more efficient way to do this? The problem is that it is not possible to use generic class definition with Selenium. – K. Khanda Apr 06 '17 at 15:07
  • You should probably add some details on the scenarios that you are trying to address, how to you plan to use these classes, etc. – JeffC Apr 06 '17 at 15:46
  • 1
    Although the FindBy annotation can be used on a type, it will not be processed by default. https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/FindBy.html. I think you will need to provide a custom implementation of the FieldDecorator and ElementLocatorFactory interface. – Grasshopper Apr 06 '17 at 16:01
  • I also thought about approach with custom Decorator and Factory. Thank you for advice and link! – K. Khanda Apr 06 '17 at 16:32

1 Answers1

1

I tried to do something similar in the past. However, it was much more simple.

Here is code snippet:

public class Table extends AbstractPageElement {

    public Table(WebElement wrappedElement, String name, String page) {
        super(wrappedElement, name, page);
    }

    public static final String ROW_XPATH_LOCATOR = "//tbody/tr";

    private static String getCellXpathLocator(int row, int column) {
        return ROW_XPATH_LOCATOR + "[" + row + "]/td[" + column + "]";
    }

    public int getRowCount() {
        return findAllByXPath(ROW_XPATH_LOCATOR).size();
    }

    public String getCellValue(int row, int column) {
        Cell cell = new Cell(row, column, this.name, this.page);
        return cell.getText();
    }


    public class Cell extends AbstractPageElement {
        private int row;
        private int column;

        public Cell(WebElement wrappedElement, String name, String page) {
            super(wrappedElement, name, page);
        }

        public Cell(int row, int column, String name, String page) {
            super(Table.this.findByXPath(getCellXpathLocator(row, column)), name, page);
            this.row = row;
            this.column = column;
        }

        public String getText() {
            return wrappedElement.getText();
        }

        public Cell nextInRow() {
            return new Cell(row, column + 1, name, page);
        }

        public Cell previousInRow() {
            return new Cell(row, column - 1, name, page);
        }

        public Cell nextInColumn() {
            return new Cell(row + 1, column, name, page);
        }

        public Cell previousInColumn() {
            return new Cell(row - 1, column, name, page);
        }
    }
}

AbstractPageElement was used with default implementation for FieldDecorator.
Project structure was like:

enter image description here

Also, you can have a look to yandex-qatools htmlelements. They created custom decorator and wrapper classes for elements.

BTW: they have implementation for Table

catch23
  • 17,519
  • 42
  • 144
  • 217