/******************************************************************************* * Copyright 2014 JHC Systems Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package jhc.redsniff.webdriver; import static jhc.redsniff.internal.finders.OnlyFinder.only; import static jhc.redsniff.internal.matchers.ContainsIgnoringWhitespace.containsIgnoringWhitespace; import static jhc.redsniff.webdriver.Finders.checkbox; import static jhc.redsniff.webdriver.Finders.elementOf; import static jhc.redsniff.webdriver.Finders.image; import static jhc.redsniff.webdriver.Finders.link; import static jhc.redsniff.webdriver.WebDriverMatchers.hasAttribute; import static jhc.redsniff.webdriver.WebDriverMatchers.hasDataRows; import static jhc.redsniff.webdriver.WebDriverMatchers.hasDataRowsIncluding; import static jhc.redsniff.webdriver.WebDriverMatchers.hasHeaders; import static jhc.redsniff.webdriver.WebDriverMatchers.hasName; import static jhc.redsniff.webdriver.WebDriverMatchers.hasSubElement; import static jhc.redsniff.webdriver.WebDriverMatchers.hasText; import static jhc.redsniff.webdriver.WebDriverMatchers.isSelected; import static jhc.redsniff.webdriver.WebDriverMatchers.isTableElementThat; import static jhc.redsniff.webdriver.WebDriverMatchers.isUnselected; import static jhc.redsniff.webdriver.WebDriverMatchers.rowConsistingOf; import static jhc.redsniff.webdriver.WebDriverMatchers.rowIncluding; import static jhc.redsniff.webdriver.finders.HtmlTagFinders.tableElement; import static jhc.redsniff.webdriver.table.TableCellInRowFinder.cell; import static jhc.redsniff.webdriver.table.TableFinder.table; import static jhc.redsniff.webdriver.table.TableRowInTableFinder.row; import static jhc.redsniff.webdriver.table.matchers.IsTableCellContaining.cellContaining; import static jhc.redsniff.webdriver.table.matchers.IsTableCellInColumn.isInColumnThat; import static jhc.redsniff.webdriver.table.matchers.IsTableCellWithText.cellWithText; import static jhc.redsniff.webdriver.table.matchers.IsTableColumn.isColumnIdentifiedBy; import static jhc.redsniff.webdriver.table.matchers.IsTableRowIncluding.includesCells; import static jhc.redsniff.webdriver.table.matchers.IsTableRowIncluding.valueInColumn; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.describedAs; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.text.IsEmptyString.isEmptyOrNullString; import jhc.redsniff.RedsniffTestBase; import jhc.redsniff.html.tables.TableCell; import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; import org.hamcrest.number.OrderingComparison; import org.junit.Test; import org.openqa.selenium.WebElement; //TODO split this up into smaller test classes by utility being tested public class WebTesterTableTest extends RedsniffTestBase { private static final Matcher<TableCell> EMPTY_HEADER = cellWithText(isEmptyOrNullString()); @Test public void assertsTableRow(){ WebElement table = t.find(only(tableElement().that(hasName("a_table")))); assertThat(table, isTableElementThat(hasHeaders("Stock Code","Stock Description","Price","Country"))); assertThat(table, isTableElementThat(hasDataRows( rowIncluding(valueInColumn("Stock Code","VOD.L"),valueInColumn("Price","1.23")), rowIncluding(valueInColumn("Stock Description","Marks And Spencer"),valueInColumn("Price","4.56")), rowIncluding(valueInColumn(4,"GB")), rowIncluding(valueInColumn("Country","US")) ))); } @Test public void complainsWithExpectationDescriptionWhenDifferentNumberOfRowsThanAsserted(){ thrown.expectMessage(containsIgnoringWhitespace("Expected: a table with data rows:\n" + "Row including: \"VOD.L\" in column <Stock Code> and \"1.23\" in column <Price>\n" + "Row including: \"Marks And Spencer\" in column <Stock Description> and \"4.56\" in column <Price>\n" + "Row including: \"GB\" in column [<4>]\n" + "Row including: \"US\" in column <Country>\n" + "Row including: \"NOTTHERE\" in column <Stock Code>\n" + " but: table had 4 rows instead of 5\n" + "\n" + "Table: \n" + "Stock Code|Stock Description|Price|Country\n" + "------------------------------------------\n" + "VOD.L|Vodafone|1.23|GB\n" + "MKS.L|Marks And Spencer|4.56|GB\n" + "TSCO.L|Tesco|7.89|GB\n" + "MCD.L|McDonalds|7.89|US")); WebElement table = t.find(only(tableElement().that(hasName("a_table")))); assertThat(table,isTableElementThat(hasHeaders("Stock Code","Stock Description","Price","Country"))); assertThat(table,isTableElementThat(hasDataRows( rowIncluding(valueInColumn("Stock Code","VOD.L"),valueInColumn("Price","1.23")), rowIncluding(valueInColumn("Stock Description","Marks And Spencer"),valueInColumn("Price","4.56")), rowIncluding(valueInColumn(4,"GB")), rowIncluding(valueInColumn("Country","US")), rowIncluding(valueInColumn("Stock Code","NOTTHERE")) ))); } @Test public void complainsWithDetailOfUnMatchedRowWhenNotMatched(){ thrown.expectMessage(containsIgnoringWhitespace( "Expected: a table with data rows:\n" + "Row including: \"VOD.L\" in column <Stock Code> and \"1.23\" in column <Price>\n" + "Row including: \"Mark And Spencer\" in column <Stock Description> and \"4.57\" in column <Price>\n" + "Row including: \"GB\" in column [<4>]\n" + "Row including: \"US\" in column <Country>\n")); thrown.expectMessage(containsIgnoringWhitespace( "but: table had:\n" + "in row 2:\n")); thrown.expectMessage(containsIgnoringWhitespace( "cell in column: [2] , headed <Stock Description>, expected to be \"Mark And Spencer\"\n" + " was:\n" + " 'Mark[s] And Spencer'\n" + "instead of:\n" + " 'Mark[] And Spencer'\n")); thrown.expectMessage(containsIgnoringWhitespace( "cell in column: [3] , headed <Price>, expected to be \"4.57\"\n" + " was:\n" + " '4.5[6]'\n" + "instead of:\n" + " '4.5[7]'\n")); thrown.expectMessage(containsIgnoringWhitespace("Actual row:\n" + "MKS.L| <!***Marks And Spencer***!>| <!***4.56***!>|GB")); WebElement table = t.find(only(tableElement().that(hasName("a_table")))); assertThat(table,isTableElementThat(hasHeaders("Stock Code","Stock Description","Price","Country"))); //TODO - figure out if can get rid of needing dataCellWithTextfix IsTableCell.with to accept string matchers as well as cell matchers assertThat(table,isTableElementThat(hasDataRows( rowIncluding(valueInColumn("Stock Code","VOD.L"),valueInColumn("Price","1.23")), rowIncluding(valueInColumn("Stock Description","Mark And Spencer"),valueInColumn("Price","4.57")), rowIncluding(valueInColumn(4,"GB")), rowIncluding(valueInColumn("Country","US")) ))); } @Test public void assertsCustomCellTypes(){ WebElement table = t.find(only(tableElement().that(hasName("a_table_with_nontext_cells")))); assertThat(table,isTableElementThat( hasHeaders("Stock Code", EMPTY_HEADER, EMPTY_HEADER, unselectedCheckboxCell()))); assertThat(table,isTableElementThat(hasDataRows( includesCells(valueInColumn("Stock Code","VOD.L"), valueInColumn(2,tradeIconCell())), rowConsistingOf( "MKS.L", tradeIconCell(), researchIconCellForIsin("MRKSSPNCRISIN"), selectedCheckboxCell() )))); } @Test public void describesErrorInCustomCellTypes(){ WebElement table = t.find(only(tableElement().that(hasName("a_table_with_nontext_cells")))); thrown.expectMessage(containsIgnoringWhitespace( "Expected: a table containing data rows:\n" + "\"MKS.L\", " + "contains : {a link that: " + "{has title \"Trade\" and " + "has href a string ending with \"#\" " + "and contains : {a image that has src a string ending with \"icon_trade.gif\"}}}, " + "contains : {a link that: " + "{has title \"Research\" and " + "has href a string ending with \"research?isin=AMRKSSPNCRISIN\" " + "and contains : {a image that has src a string ending with \"icon_research.gif\"}}}," + "CheckboxCell:SELECTED")); thrown.expectMessage(containsIgnoringWhitespace( "but: table had:\n" + "in row 2:\n"+ "cell in column: [3] , (with blank header), " + "expected to be " + "contains : {a link that: " + "{has title \"Research\" and " + "has href a string ending with \"research?isin=AMRKSSPNCRISIN\" " + "and contains : {a image that has src a string ending with \"icon_research.gif\"}}}" + "child elements did not match:\n" + "Not found - but searching for link that: "+ "{has title \"Research\" and " + "has href a string ending with \"research?isin=AMRKSSPNCRISIN\"} " + "<a> (id:link71) - " + "not matched because href was ")); //can't really include file path here - consider only outputting end bit assertThat(table,isTableElementThat(hasDataRowsIncluding( rowConsistingOf("MKS.L", tradeIconCell(), researchIconCellForIsin("AMRKSSPNCRISIN"), selectedCheckboxCell() )))); } private static Matcher<TableCell> unselectedCheckboxCell() { return describedAs("CheckboxCell:UNSELECTED",cellContaining(checkbox().that(isUnselected()))); } private static Matcher<TableCell> selectedCheckboxCell() { return describedAs("CheckboxCell:SELECTED",cellContaining(checkbox().that(isSelected()))); } private Matcher<TableCell> researchIconCellForIsin(String isin) { return cellContaining(link() .that(hasTitle(equalTo("Research"))) .that(hasHref(endsWith("research?isin=" + isin))) .that(hasSubElement( image().that(hasSrc(endsWith("icon_research.gif")))))); } private static Matcher<TableCell> tradeIconCell() { return cellContaining(link() .that(hasTitle(equalTo("Trade"))) .that(hasHref(endsWith("#"))) .that(hasSubElement( image().that(hasSrc(endsWith("icon_trade.gif")))))); } private static Matcher<WebElement> hasSrc(Matcher<String> srcMatcher) { return hasAttribute("src","src", srcMatcher); } private static Matcher<WebElement> hasTitle(Matcher<String> titleMatcher) { return hasAttribute("title", "title", titleMatcher); } private static Matcher<WebElement> hasHref(Matcher<String> stringMatcher) { return hasAttribute("href", "href", stringMatcher); } @Test public void complainsOfUnCheckedCheckbox(){ thrown.expectMessage(containsIgnoringWhitespace( "Expected: a table containing data rows:\n" + "Row including: \"VOD.L\" in column <Stock Code> and CheckboxCell:SELECTED in column [<4>]\n")); thrown.expectMessage(containsIgnoringWhitespace( "in row 1:\n" +" cell in column: [4] , (with blank header), expected to be CheckboxCell:SELECTED\n" +"child elements did not match:\n" +"Not found - \n" +"<input> (name:selectItemBox1) - not matched because element was <unselected>\n")); WebElement table = t.find(only(tableElement().that(hasName("a_table_with_nontext_cells")))); assertThat(table,isTableElementThat(hasDataRowsIncluding( rowIncluding(valueInColumn("Stock Code","VOD.L"), valueInColumn(4, selectedCheckboxCell() ) ) ))); } @Test public void parsesLargeTableInReasonableTime(){ thrown.expect(AssertionError.class); WebElement table = t.find(only(tableElement().that(hasName("a_large_table_with_11_cols_34_rows")))); long timeBefore = System.currentTimeMillis(); //TODO - figure out if can get rid of needing dataCellWithTextfix IsTableCell.with to accept string matchers as well as cell matchers assertThat(table,isTableElementThat(hasDataRows( includesCells(valueInColumn("Stock Code",cellWithText(startsWith("VOD.L"))), valueInColumn("Price","1.23")), includesCells(valueInColumn("Stock Description",cellWithText(startsWith("Marks"))), valueInColumn("Price","4.56")), includesCells(valueInColumn(4,"GB")), includesCells(valueInColumn("Country","US"))))); int timeTakenSecs = (int) ((System.currentTimeMillis()-timeBefore)/1000l); System.out.println("completed in " + timeTakenSecs + " seconds"); assertThat("completes in less than 10 seconds",timeTakenSecs,OrderingComparison.lessThan(10)); } @Test public void assertsTableIncludesRows(){ WebElement table = t.find(only(tableElement().that(hasName("a_table")))); assertThat(table,isTableElementThat(hasDataRowsIncluding( includesCells(valueInColumn("Stock Code","VOD.L"),valueInColumn("Stock Description","Vodafone"))))); } @Test public void findsRowByValueInAColumn(){ t.assertThatThe( only (elementOf( cell().that( isInColumnThat(isColumnIdentifiedBy("Price"))) .withinA(row().that(includesCells(valueInColumn("Stock Code", "MKS.L")))) .withinA(table(tableElement().that(hasName("a_table")))))), hasText("4.56")); } @Test public void describesFinderOfRowByValueInAColumn(){ assertHasDescription(cell().that( isInColumnThat(isColumnIdentifiedBy("Price"))) .withinA(row().that(includesCells(valueInColumn("Stock Code", "MKS.L")))) .withinA(table(tableElement().that(hasName("a_table")))), "cell that is in column <Price> within:\n"+ " a data row that includes cells: \"MKS.L\" in column <Stock Code>, " + "within a table object formed from table that has name \"a_table\""); } @Test public void assertsTableRowUsingTableFinders(){ thrown.expectMessage(containsIgnoringWhitespace("Expected: a data row that includes cells: \"MAKS.L\" in column <Stock Code>" + ", within a table object formed from table that has name \"a_table\"")); thrown.expectMessage(containsIgnoringWhitespace("within: Table: \n" + "Stock Code|Stock Description|Price|Country\n" + "------------------------------------------\n" + "VOD.L|Vodafone|1.23|GB\n" + "MKS.L|Marks And Spencer|4.56|GB")); thrown.expectMessage(containsIgnoringWhitespace("Not found - nearest matches:\n" + "VOD.L|Vodafone|1.23|GB - not matched because \n" + " cell in column: [1] , headed <Stock Code>, expected to be \"MAKS.L\"\n" + " was:\n" + " '[VOD].L'\n" + "instead of:\n" + " '[MAKS].L'")); t.assertPresenceOf(row().that(includesCells(valueInColumn("Stock Code", "MAKS.L"))).withinA(table(tableElement().that(hasName("a_table"))))); } @Test public void assertsTableRowUsingTableMatchers(){ WebElement table = t.find(only(tableElement().that(hasName("a_table")))); MatcherAssert.assertThat(table,WebDriverMatchers.isTableElementThat( WebDriverMatchers.hasDataRowsIncluding( WebDriverMatchers.rowIncluding(WebDriverMatchers.valueInColumn("Stock Code","MKS.L"))))); } }