com.technophobia.webdriver.substeps.impl.TableSubStepImplementations.java Source code

Java tutorial

Introduction

Here is the source code for com.technophobia.webdriver.substeps.impl.TableSubStepImplementations.java

Source

/*
 *   Copyright Technophobia Ltd 2012
 *
 *   This file is part of Substeps.
 *
 *    Substeps is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    Substeps is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with Substeps.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.technophobia.webdriver.substeps.impl;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase;

import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import com.google.common.base.Supplier;
import com.technophobia.substeps.model.SubSteps.Step;
import com.technophobia.substeps.model.SubSteps.StepImplementations;
import com.technophobia.substeps.model.SubSteps.StepParameter;
import com.technophobia.substeps.model.parameter.IntegerConverter;
import com.technophobia.webdriver.substeps.runner.DefaultExecutionSetupTearDown;
import com.technophobia.webdriver.util.WebDriverContext;
import com.technophobia.webdriver.util.WebDriverSubstepsBy;

@StepImplementations(requiredInitialisationClasses = DefaultExecutionSetupTearDown.class)
public class TableSubStepImplementations extends AbstractWebDriverSubStepImplementations {

    /*
     * TODO
     * 
     * a method that takes a table with column names - stash in the context for
     * reference and look up the index could combine this - not sure what
     * purpose the column names serves... see nhs proxy user feature (low) and
     * Then the current contracts list will contain the following
     * ContractSearchSteps.thenTheContractsListContains
     * 
     * Assert table contains row - a method that takes a map of values, use the
     * stash for the index
     * 
     * find a table - findby id etc..
     * 
     * assert row x has values <array> - can't pass a single row of values..
     * 
     * combinations with passing in the table id
     */

    /**
     * Locates the table body row, assuming that the table has already been
     * located Row 1 is the first
     * &lt;tr&gt;
     * beneath a &lt;tbody&gt;
     * 
     * @example FindTableBodyRow row 3
     * @section Table
     *
     * @param row
     *            1 based row index
     * @return
     *  the web element
     */
    @Step("FindTableBodyRow row ([^\"]*)")
    public WebElement findTableBodyRow(@StepParameter(converter = IntegerConverter.class) final Integer row) {

        // assumes current element is already set
        final WebElement currentElem = webDriverContext().getCurrentElement();

        AssertionWebDriverSubStepImplementations.assertElementIs(currentElem, "table");

        final WebElement tbody = getResultsTableBodyElement(currentElem);

        final WebElement rowElement = getTableRow(tbody, row);

        Assert.assertNotNull("expecting a table row element", rowElement);
        webDriverContext().setCurrentElement(rowElement);

        webDriverContext().stashElement(TABLE_ROW_KEY, rowElement);
        return rowElement;
    }

    // TODO can't implement this until worked out how to pass single rows
    // through

    // @Step("AssertTable row ([^\"]*) contains values")
    // public void assertTableRowContainsValues(@StepParameter(converter =
    // IntegerConverter.class)final Integer row,
    // final List<Map<String, String>> expectedResults){
    //
    // Assert.assertNotNull("expecting a table of results to be specified",
    // expectedResults);
    // Assert.assertThat("only expecting 1 row in table data",
    // expectedResults.size(), is(1));
    // //
    //
    // final WebElement tableRow = findTableBodyRow(row);
    //
    //
    // final List<WebElement> columnElements =
    // tableRow.findElements(By.tagName("td"));
    //
    // if (columnElements != null) {
    //
    // if (table == null) {
    // table = new ArrayList<Map<String, String>>();
    // }
    // final Map<String, String> rowMap = new HashMap<String, String>();
    // table.add(rowMap);
    //
    // for (int i = 0; i < columnElements.size(); i++) {
    // rowMap.put(columnHeadings[i], columnElements.get(i).getText());
    // }
    // }
    // }

    /**
     * Check that a table cell contains the specified text using a 1 based
     * index. Row 1 is the first
     * &lt;tr&gt;
     * beneath a &lt;tbody&gt;
     * 
     * @example AssertTableValue column 2, row 3 contains text "Hello Bob"
     * @section Table
     * 
     * @param column
     *            1 based column index
     * @param row
     *            1 based row index
     * @param text
     *            the expected text
     */
    @Step("AssertTableValue column ([^\"]*), row ([^\"]*) contains text \"([^\"]*)\"")
    public void assertTableValue(@StepParameter(converter = IntegerConverter.class) final Integer column,
            @StepParameter(converter = IntegerConverter.class) final Integer row, final String text) {

        // assumes current element is already set
        final WebElement currentElem = webDriverContext().getCurrentElement();

        AssertionWebDriverSubStepImplementations.assertElementIs(currentElem, "table");

        final WebElement tbody = getResultsTableBodyElement(currentElem);

        final String cellText = getValueInResultsTable(tbody, column.intValue(), row.intValue());
        Assert.assertNotNull("expecting some cell text", cellText);

        Assert.assertTrue("expecting cell text to contain: " + text + " actual: " + cellText,
                cellText.contains(text));

    }

    /**
     * Step implementation to be used after a table and specific row, assert that the given column has the specified  text
     * @example AssertColumn 2 text = "Mr A. Person"
     * @section Table
     * @param column the column number (1 based)
     * @param text the expected text
     */
    @Step("AssertColumn (\\d+) text = \"([^\"]*)\"")
    public void assertColumnText(@StepParameter(converter = IntegerConverter.class) final Integer column,
            final String text) {

        // assumes current element is already set
        final WebElement rowElem = webDriverContext().getCurrentElement();

        AssertionWebDriverSubStepImplementations.assertElementIs(rowElem, "tr");

        WebElement cell = getCell(rowElem, column);

        webDriverContext().setCurrentElement(cell);

        String cellText = cell.getText();

        Assert.assertNotNull("expecting some cell text", cellText);

        Assert.assertThat("expecting cell text to = " + text, cellText, is(text));

    }

    private WebElement getResultsTableBodyElement(final WebElement tableElement) {

        Assert.assertNotNull("expecting a tableElement", tableElement);

        final List<WebElement> tbodyElems = tableElement.findElements(By.tagName("tbody"));
        Assert.assertNotNull("expecting th row elems", tbodyElems);
        Assert.assertThat("expecting count of 1", tbodyElems.size(), is(1));

        final WebElement tbody = tbodyElems.get(0);
        Assert.assertNotNull("expecting tbody elem", tbody);

        return tbody;
    }

    private WebElement getTableRow(final WebElement tbody, final int row) {
        final List<WebElement> rowElements = tbody.findElements(By.tagName("tr"));
        Assert.assertNotNull("expecting th row elems", rowElements);

        Assert.assertTrue("expecting more than " + row + " row in the table", rowElements.size() >= row);

        // row parameter will be 1 based, but we need to discard the header row
        final WebElement rowElement = rowElements.get(row - 1);
        Assert.assertNotNull("expecting a tr at tbody idx: " + (row - 1), rowElement);
        return rowElement;
    }

    public String getValueInResultsTable(final WebElement tbody, final int col, final int row) {

        final WebElement rowElement = getTableRow(tbody, row);

        //        final List<WebElement> columnElements = rowElement.findElements(By.tagName("td"));
        //        Assert.assertNotNull("expecting columnElements", columnElements);
        //
        //        Assert.assertTrue("expecting more than " + col + " columns in the table, got: " + columnElements.size(),
        //                columnElements.size() >= col);

        final WebElement tdElem = getCell(rowElement, col);

        Assert.assertNotNull("expecting a td at column: " + col, tdElem);

        return tdElem.getText();
    }

    private WebElement getCell(WebElement rowElement, final int col) {
        final List<WebElement> columnElements = rowElement.findElements(By.tagName("td"));
        Assert.assertNotNull("expecting columnElements", columnElements);

        Assert.assertTrue("expecting more than " + col + " columns in the table, got: " + columnElements.size(),
                columnElements.size() >= col);
        final WebElement tdElem = columnElements.get(col - 1);

        Assert.assertNotNull("expecting a td at column: " + col, tdElem);
        return tdElem;
    }

    //

    /**
     * Find a row in a table where columns exist that contain the specified
     * text. Not all columns of the table need to specified, however the order
     * is important. Finding multiple matching results will result in an error.
     * 
     * Once the row has been located, other FindInRow methods can be used that
     * may in turn refer to and set the 'Current Element', this method does not
     * set the current element for that reason.
     * 
     * @example FindTableRowWithColumnsThatContainText
     *          ["My Name","Where it all began...","December 19 2012"]
     * @section Table
     * 
     * @param columnText
     *            A comma delimitted list of column values, each column can be
     *            double quoted
     */
    @Step("FindTableRowWithColumnsThatContainText \\[(.*)\\]")
    public void findRowInTableWithText(final String columnText) {

        final WebElement currentElement = webDriverContext().getCurrentElement();

        Assert.assertThat("expecting the current element to be a table", currentElement.getTagName(),
                equalToIgnoringCase("table"));

        final String[] columnValues = columnText.split(",");
        final List<String> columnValList = new ArrayList<String>();
        for (final String s : columnValues) {
            columnValList.add(s.replaceAll("\"", "").trim());
        }

        final List<WebElement> tableRows = currentElement.findElements(By.tagName("tr"));

        List<WebElement> matchingRows = null;

        // TODO - refactor this into WebDriver Bys ..?

        // go through all rows
        for (final WebElement row : tableRows) {

            // for each row
            final List<WebElement> tableCells = row.findElements(By.tagName("td"));

            int lookingForIdx = 0;

            boolean found = false;
            // do we have a match ?
            for (final WebElement td : tableCells) {

                if (td.getText().contains(columnValList.get(lookingForIdx))) {

                    lookingForIdx++;
                    if (lookingForIdx >= columnValList.size()) {
                        // found em all
                        found = true;
                        break;
                    }
                }
            }

            if (found) {
                if (matchingRows == null) {
                    matchingRows = new ArrayList<WebElement>();
                }
                matchingRows.add(row);
            }

        }

        Assert.assertNotNull("Didn't find any rows with values: [" + columnText + "]", matchingRows);

        Assert.assertThat("Found too many rows that match values: [" + columnText + "]", matchingRows.size(),
                is(1));

        webDriverContext().stashElement(TABLE_ROW_KEY, matchingRows.get(0));
    }

    /**
     * Find an element within a table row by tag and attributes.
     * 
     * @example FindElementInRow ByTagAndAttributes tag="a"
     *          attributes=[class="link-class",....]
     * @section Table
     * @param tag
     *            the tag
     * @param attributeString
     *            the attribute string
     */
    @Step("FindElementInRow ByTagAndAttributes tag=\"?([^\"]*)\"? attributes=\\[(.*)\\]")
    public void findLinkInRowByTagAndAttributes(final String tag, final String attributeString) {

        final By by = WebDriverSubstepsBy.ByTagAndAttributes(tag, attributeString);

        findElementInRowBy(by);
    }

    /**
     * Find a link (anchor) element within a table row using the link text as a
     * discriminator.
     * 
     * @example FindElementInRow linkText="View"
     * @section Table
     * @param linkText
     *            the text of the link to find
     */
    @Step("FindElementInRow linkText=\"([^\"]*)\"")
    public void findLinkInRow(final String linkText) {

        final By by = By.linkText(linkText);

        findElementInRowBy(by);
    }

    private static final String TABLE_ROW_KEY = "_tr_stash_key";

    private WebElement findElementInRowBy(final By by) {

        webDriverContext().setCurrentElement(null);

        final WebElement row = webDriverContext().getElementFromStash(TABLE_ROW_KEY);

        Assert.assertThat("expecting the current element to be a table", row.getTagName(),
                equalToIgnoringCase("tr"));

        // go through all td's in this row, collect all elements that match the
        // by

        final List<WebElement> tableCells = row.findElements(By.tagName("td"));

        List<WebElement> matchingElements = null;

        for (final WebElement e : tableCells) {

            final List<WebElement> foundElements = e.findElements(by);
            if (foundElements != null && !foundElements.isEmpty()) {

                if (matchingElements == null) {
                    matchingElements = new ArrayList<WebElement>();
                }
                matchingElements.addAll(foundElements);
            }
        }

        Assert.assertNotNull("expecting to have found some elements", matchingElements);
        Assert.assertThat("Found too many elements in the row", matchingElements.size(), is(1));

        final WebElement current = matchingElements.get(0);
        webDriverContext().setCurrentElement(current);

        return current;
    }

}