diff --git a/src/SeleniumLibrary/keywords/tableelement.py b/src/SeleniumLibrary/keywords/tableelement.py index ffb0bcbfe..72a483958 100644 --- a/src/SeleniumLibrary/keywords/tableelement.py +++ b/src/SeleniumLibrary/keywords/tableelement.py @@ -20,179 +20,175 @@ class TableElementKeywords(LibraryComponent): @keyword - def get_table_cell(self, table_locator, row, column, loglevel='INFO'): - """Returns the content from a table cell. + def get_table_cell(self, locator, row, column, loglevel='INFO'): + """Returns contents of table cell. - Row and column number start from 1. Header and footer rows are - included in the count. A negative row or column number can be used - to get rows counting from the end (end: -1). Cell content from header - or footer rows can be obtained with this keyword. To understand how - tables are identified, please take a look at the `introduction`. + The table is located using the ``locator`` argument and its cell + found using ``row`` and ``column``. See the `Locating elements` + section for details about the locator syntax. - See `Page Should Contain` for explanation about `loglevel` argument. + Both row and column indexes start from 1, and header and footer + rows are included in the count. It is possible to refer to rows + and columns from the end by using negative indexes so that -1 + is the last row/column, -2 is the second last, and so on. + + All ```` and ```` elements anywhere in the table are + considered to be cells. + + See `Page Should Contain` for explanation about the ``loglevel`` + argument. """ row = int(row) - row_index = row - if row > 0: - row_index = row - 1 column = int(column) - column_index = column - if column > 0: - column_index = column - 1 - table = self.element_finder.find(table_locator) - if table: - rows = table.find_elements_by_xpath("./thead/tr") - if row_index >= len(rows) or row_index < 0: - rows.extend(table.find_elements_by_xpath("./tbody/tr")) - if row_index >= len(rows) or row_index < 0: - rows.extend(table.find_elements_by_xpath("./tfoot/tr")) - if row_index < len(rows): - columns = rows[row_index].find_elements_by_tag_name('th') - if column_index >= len(columns) or column_index < 0: - columns.extend(rows[row_index].find_elements_by_tag_name('td')) - if column_index < len(columns): - return columns[column_index].text - self.ctx.log_source(loglevel) - raise AssertionError("Cell in table %s in row #%s and column #%s " - "could not be found." - % (table_locator, str(row), str(column))) + if row == 0 or column == 0: + raise ValueError('Both row and column must be non-zero, ' + 'got row %d and column %d.' % (row, column)) + try: + cell = self._get_cell(locator, row, column) + except AssertionError: + self.log_source(loglevel) + raise + return cell.text + + def _get_cell(self, locator, row, column): + rows = self._get_rows(locator, row) + if len(rows) < abs(row): + raise AssertionError("Table '%s' should have had at least %d " + "rows but had only %d." + % (locator, abs(row), len(rows))) + index = row - 1 if row > 0 else row + cells = rows[index].find_elements_by_xpath('./th|./td') + if len(cells) < abs(column): + raise AssertionError("Table '%s' row %d should have had at " + "least %d columns but had only %d." + % (locator, row, abs(column), len(cells))) + index = column - 1 if column > 0 else column + return cells[index] + + def _get_rows(self, locator, count): + # Get rows in same order as browsers render them. + table = self.find_element(locator, tag='table') + rows = table.find_elements_by_xpath("./thead/tr") + if count < 0 or len(rows) < count: + rows.extend(table.find_elements_by_xpath("./tbody/tr")) + if count < 0 or len(rows) < count: + rows.extend(table.find_elements_by_xpath("./tfoot/tr")) + return rows @keyword - def table_cell_should_contain(self, table_locator, row, column, expected, loglevel='INFO'): - """Verifies that a certain cell in a table contains `expected`. - - Row and column number start from 1. This keyword passes if the - specified cell contains the given content. If you want to test - that the cell content matches exactly, or that it e.g. starts - with some text, use `Get Table Cell` keyword in combination - with built-in keywords such as `Should Be Equal` or `Should - Start With`. + def table_cell_should_contain(self, locator, row, column, expected, loglevel='INFO'): + """Verifies table cell contains text ``expected``. - To understand how tables are identified, please take a look at - the `introduction`. - - See `Page Should Contain` for explanation about `loglevel` argument. + See `Get Table Cell` that this keyword uses internally for + explanation about accepted arguments. """ - message = ("Cell in table '%s' in row #%s and column #%s " - "should have contained text '%s'." - % (table_locator, row, column, expected)) - try: - content = self.get_table_cell(table_locator, row, column, loglevel='NONE') - except AssertionError as err: - self.info(err) - self.ctx.log_source(loglevel) - raise AssertionError(message) - self.info("Cell contains %s." % (content)) + content = self.get_table_cell(locator, row, column, loglevel) if expected not in content: self.ctx.log_source(loglevel) - raise AssertionError(message) + raise AssertionError("Table '%s' cell on row %s and column %s " + "should have contained text '%s' but it had " + "'%s'." + % (locator, row, column, expected, content)) + self.info("Table cell contains '%s'." % content) @keyword - def table_column_should_contain(self, table_locator, col, expected, loglevel='INFO'): - """Verifies that a specific column contains `expected`. + def table_column_should_contain(self, locator, column, expected, loglevel='INFO'): + """Verifies table column contains text ``expected``. - The first leftmost column is column number 1. A negative column - number can be used to get column counting from the end of the row (end: -1). - If the table contains cells that span multiple columns, those merged cells - count as a single column. For example both tests below work, - if in one row columns A and B are merged with colspan="2", and - the logical third column contains "C". + The table is located using the ``locator`` argument and its column + found using ``column``. See the `Locating elements` section for + details about the locator syntax. - Example: - | Table Column Should Contain | tableId | 3 | C | - | Table Column Should Contain | tableId | 2 | C | + Column indexes start from 1. It is possible to refer to columns + from the end by using negative indexes so that -1 is the last column, + -2 is the second last, and so on. - To understand how tables are identified, please take a look at - the `introduction`. + If a table contains cells that span multiple columns, those merged + cells count as a single column. - See `Page Should Contain Element` for explanation about - `loglevel` argument. + See `Page Should Contain Element` for explanation about the + ``loglevel`` argument. """ - element = self.table_element_finder.find_by_col(table_locator, col, - expected) + element = self.table_element_finder.find_by_column(locator, column, expected) if element is None: self.ctx.log_source(loglevel) - raise AssertionError("Column #%s in table identified by '%s' " - "should have contained text '%s'." - % (col, table_locator, expected)) + raise AssertionError("Table '%s' column %s did not contain text " + "'%s'." % (locator, column, expected)) @keyword - def table_footer_should_contain(self, table_locator, expected, loglevel='INFO'): - """Verifies that the table footer contains `expected`. + def table_footer_should_contain(self, locator, expected, loglevel='INFO'): + """Verifies table footer contains text ``expected``. - With table footer can be described as any -element that is - child of a -element. To understand how tables are - identified, please take a look at the `introduction`. + Any ```` element inside ```` element is considered to + be part of the footer. - See `Page Should Contain Element` for explanation about - `loglevel` argument. + The table is located using the ``locator`` argument. See the + `Locating elements` section for details about the locator syntax. + + See `Page Should Contain Element` for explanation about the + ``loglevel`` argument. """ - element = self.table_element_finder.find_by_footer(table_locator, - expected) + element = self.table_element_finder.find_by_footer(locator, expected) if element is None: self.ctx.log_source(loglevel) - raise AssertionError("Footer in table identified by '%s' " - "should have contained " - "text '%s'." % (table_locator, expected)) + raise AssertionError("Table '%s' footer did not contain text " + "'%s'." % (locator, expected)) @keyword - def table_header_should_contain(self, table_locator, expected, loglevel='INFO'): - """Verifies that the table header, i.e. any ... element, contains `expected`. + def table_header_should_contain(self, locator, expected, loglevel='INFO'): + """Verifies table header contains text ``expected``. + + Any ```` element anywhere in the table is considered to be + part of the header. - To understand how tables are identified, please take a look at - the `introduction`. + The table is located using the ``locator`` argument. See the + `Locating elements` section for details about the locator syntax. - See `Page Should Contain Element` for explanation about - `loglevel` argument. + See `Page Should Contain Element` for explanation about the + ``loglevel`` argument. """ - element = self.table_element_finder.find_by_header(table_locator, - expected) + element = self.table_element_finder.find_by_header(locator, expected) if element is None: self.ctx.log_source(loglevel) - raise AssertionError("Header in table identified by '%s' should " - "have contained " - "text '%s'." % (table_locator, expected)) + raise AssertionError("Table '%s' header did not contain text " + "'%s'." % (locator, expected)) @keyword - def table_row_should_contain(self, table_locator, row, expected, loglevel='INFO'): - """Verifies that a specific table row contains `expected`. - - The uppermost row is row number 1. A negative column - number can be used to get column counting from the end of the row - (end: -1). For tables that are structured with thead, tbody and tfoot, - only the tbody section is searched. Please use `Table Header Should Contain` - or `Table Footer Should Contain` for tests against the header or - footer content. - - If the table contains cells that span multiple rows, a match - only occurs for the uppermost row of those merged cells. To - understand how tables are identified, please take a look at - the `introduction`. - - See `Page Should Contain Element` for explanation about `loglevel` argument. + def table_row_should_contain(self, locator, row, expected, loglevel='INFO'): + """Verifies that table row contains text ``expected``. + + The table is located using the ``locator`` argument and its column + found using ``column``. See the `Locating elements` section for + details about the locator syntax. + + Row indexes start from 1. It is possible to refer to rows + from the end by using negative indexes so that -1 is the last row, + -2 is the second last, and so on. + + If a table contains cells that span multiple rows, a match + only occurs for the uppermost row of those merged cells. + + See `Page Should Contain Element` for explanation about the + ``loglevel`` argument. """ - element = self.table_element_finder.find_by_row(table_locator, - row, expected) + element = self.table_element_finder.find_by_row(locator, row, expected) if element is None: self.ctx.log_source(loglevel) - raise AssertionError("Row #%s in table identified by '%s' " - "should have contained " - "text '%s'." % (row, table_locator, expected)) + raise AssertionError("Table '%s' row %s did not contain text " + "'%s'." % (locator, row, expected)) @keyword - def table_should_contain(self, table_locator, expected, loglevel='INFO'): - """Verifies that `expected` can be found somewhere in the table. + def table_should_contain(self, locator, expected, loglevel='INFO'): + """Verifies table contains text ``expected``. - To understand how tables are identified, please take a look at - the `introduction`. + The table is located using the ``locator`` argument. See the + `Locating elements` section for details about the locator syntax. - See `Page Should Contain Element` for explanation about - `loglevel` argument. + See `Page Should Contain Element` for explanation about the + ``loglevel`` argument. """ - element = self.table_element_finder.find_by_content(table_locator, - expected) + element = self.table_element_finder.find_by_content(locator, expected) if element is None: self.ctx.log_source(loglevel) - raise AssertionError("Table identified by '%s' should have " - "contained text '%s'." - % (table_locator, expected)) + raise AssertionError("Table '%s' did not contain text '%s'." + % (locator, expected)) diff --git a/src/SeleniumLibrary/locators/tableelementfinder.py b/src/SeleniumLibrary/locators/tableelementfinder.py index 3d86eada9..054a5000a 100644 --- a/src/SeleniumLibrary/locators/tableelementfinder.py +++ b/src/SeleniumLibrary/locators/tableelementfinder.py @@ -18,57 +18,42 @@ class TableElementFinder(ContextAware): - locators = { - 'content': ['//*'], - 'header': ['//th'], - 'footer': ['//tfoot//td'], - 'row': ['//tr[{row}]//*'], - 'last-row': ['//tbody/tr[position()=last()-({row}-1)]'], - 'col': ['//tr//*[self::td or self::th][{col}]'], - 'last-col': ['//tbody/tr/td[position()=last()-({col}-1)]', - '//tbody/tr/td[position()=last()-({col}-1)]'] - } def find_by_content(self, table_locator, content): - locators = self.locators['content'] - return self._search_in_locators(table_locator, locators, content) + return self._find(table_locator, '//*', content) def find_by_header(self, table_locator, content): - locators = self.locators['header'] - return self._search_in_locators(table_locator, locators, content) + return self._find(table_locator, '//th', content) def find_by_footer(self, table_locator, content): - locators = self.locators['footer'] - return self._search_in_locators(table_locator, locators, content) + return self._find(table_locator, '//tfoot//td', content) def find_by_row(self, table_locator, row, content): - location_method = "row" - row = str(row) - if row[0] == "-": - row = row[1:] - location_method = "last-row" - locators = [locator.format(row=row) - for locator in self.locators[location_method]] - return self._search_in_locators(table_locator, locators, content) - - def find_by_col(self, table_locator, col, content): - location_method = "col" - col = str(col) - if col[0] == "-": - col = col[1:] - location_method = "last-col" - locators = [locator.format(col=col) - for locator in self.locators[location_method]] - return self._search_in_locators(table_locator, locators, content) - - def _search_in_locators(self, table_locator, locators, content): + position = self._index_to_position(row) + locator = '//tr[{}]'.format(position) + return self._find(table_locator, locator, content) + + def find_by_column(self, table_locator, col, content): + position = self._index_to_position(col) + locator = '//tr//*[self::td or self::th][{}]'.format(position) + return self._find(table_locator, locator, content) + + def _index_to_position(self, index): + index = int(index) + if index == 0: + raise ValueError('Row and column indexes must be non-zero.') + if index > 0: + return str(index) + if index == -1: + return 'position()=last()' + return 'position()=last()-{}'.format(abs(index) - 1) + + def _find(self, table_locator, locator, content): table = self.find_element(table_locator) - for locator in locators: - elements = self.find_elements(locator, parent=table) - for element in elements: - if content is None: - return element - element_text = element.text - if element_text and content in element_text: - return element + elements = self.find_elements(locator, parent=table) + for element in elements: + if content is None: + return element + if element.text and content in element.text: + return element return None diff --git a/test/acceptance/keywords/tables/col_should_contain.robot b/test/acceptance/keywords/tables/col_should_contain.robot index ddcffaedb..424c90418 100644 --- a/test/acceptance/keywords/tables/col_should_contain.robot +++ b/test/acceptance/keywords/tables/col_should_contain.robot @@ -3,27 +3,40 @@ Resource table_resource.robot *** Test Cases *** Should Find Text In Specific Column - [Template] Table Column Should Contain With CSS And XPath Locators - simpleTable 2 simpleTable_B2 - simpleWithNested 2 nestedTable_A1 - nestedTable 3 nestedTable_C1 + [Template] Table Column Should Contain + simpleTable 2 simpleTable_B2 + id:simpleTable -2 simpleTable_B2 + simpleWithNested 2 nestedTable_A1 + css:#nestedTable 3 nestedTable_C1 + nestedTable -1 nestedTable_C1 tableWithSingleHeader 1 tableWithSingleHeader_A1 tableWithSingleHeader 1 tableWithSingleHeader_A3 - tableWithTwoHeaders 2 tableWithTwoHeaders_B2 + tableWithTwoHeaders 2 tableWithTwoHeaders_B2 + +Mixed th and td + [Template] Table Column Should Contain + mixed-th-td 1 1.1 (th) + id:mixed-th-td 1 2.1 (td) + css:#mixed-th-td 2 1.2 (td) + //*[@id="mixed-th-td"] 2 2.2 (th) + mixed-th-td 3 2.3 (td) + mixed-th-td 3 3.3 (th) + mixed-th-td -2 1.2 (td) + mixed-th-td -2 2.2 (th) + mixed-th-td -3 1.1 (th) + mixed-th-td -3 2.1 (td) Should Give Error Message When Content Not Found In Table Column Run Keyword And Expect Error - ... Column #2 in table identified by 'id:simpleTable' should have contained text 'simpleTable_C3'. + ... Table 'id:simpleTable' column 2 did not contain text 'simpleTable_C3'. ... Table Column Should Contain id:simpleTable 2 simpleTable_C3 Should Give Error Message When Column Number Out Of Bounds Run Keyword And Expect Error - ... Column #20 in table identified by 'xpath=//*[@id="simpleTable"]' should have contained text 'simpleTable_B3'. - ... Table Column Should Contain xpath=//*[@id="simpleTable"] 20 simpleTable_B3 + ... Table '//*[@id="simpleTable"]' column 20 did not contain text 'simpleTable_B3'. + ... Table Column Should Contain //*[@id="simpleTable"] 20 simpleTable_B3 -*** Keywords *** -Table Column Should Contain With CSS And XPath Locators - [Documentation] Table Column Should Contain With CSS And XPath Locators - [Arguments] ${table id} ${col} ${expected} - Run Table Keyword With CSS And XPath Locators - ... Table Column Should Contain ${table id} ${col} ${expected} +Zero is invalid column index + Run Keyword And Expect Error + ... ValueError: Row and column indexes must be non-zero. + ... Table Column Should Contain simpleTable 0 xxx diff --git a/test/acceptance/keywords/tables/footer_should_contain.robot b/test/acceptance/keywords/tables/footer_should_contain.robot index 3554212eb..e414418cc 100644 --- a/test/acceptance/keywords/tables/footer_should_contain.robot +++ b/test/acceptance/keywords/tables/footer_should_contain.robot @@ -1,22 +1,15 @@ *** Settings *** -Documentation Tests for table footer Resource table_resource.robot *** Test Cases *** Should Find Text In Footer - [Template] Table Footer Should Contain With CSS And XPath Locators - withHeadAndFoot withHeadAndFoot_AF1 - withHeadAndFoot withHeadAndFoot_CF1 - withHeadAndFoot withHeadAndFoot_AF2 - withHeadAndFoot withHeadAndFoot_CF2 + [Template] Table Footer Should Contain + withHeadAndFoot withHeadAndFoot_AF1 + id:withHeadAndFoot withHeadAndFoot_CF1 + css:#withHeadAndFoot withHeadAndFoot_AF2 + withHeadAndFoot withHeadAndFoot_CF2 Should Give Error Message When Content Not Found In Table Footer Run Keyword And Expect Error - ... Footer in table identified by 'withHeadAndFoot' should have contained text 'withHeadAndFoot_B2'. + ... Table 'withHeadAndFoot' footer did not contain text 'withHeadAndFoot_B2'. ... Table Footer Should Contain withHeadAndFoot withHeadAndFoot_B2 - -*** Keywords *** -Table Footer Should Contain With CSS And XPath Locators - [Arguments] ${tableId} ${content} - Run Table Keyword With CSS And XPath Locators - ... Table Footer Should Contain ${table id} ${content} diff --git a/test/acceptance/keywords/tables/get_table_cell.robot b/test/acceptance/keywords/tables/get_table_cell.robot index 125ec38bf..ed58a658a 100644 --- a/test/acceptance/keywords/tables/get_table_cell.robot +++ b/test/acceptance/keywords/tables/get_table_cell.robot @@ -1,40 +1,64 @@ *** Settings *** -Documentation Tests cell contents Resource table_resource.robot *** Test Cases *** Should Retrieve Text From Cell - [Template] Table Cell Should Be Equal With CSS And XPath Locators - simpleTable 1 1 simpleTable_A1 + [Template] Table Cell Should Be Equal + simpleTable 1 1 simpleTable_A1 + id:simpleTable -1 -1 simpleTable_C3 tableWithSingleHeader 1 1 tableWithSingleHeader_A1 tableWithSingleHeader 3 3 tableWithSingleHeader_C3 - withHeadAndFoot 1 2 withHeadAndFoot_BH1 - withHeadAndFoot 4 3 withHeadAndFoot_C2 - withHeadAndFoot 6 1 withHeadAndFoot_AF1 - mergedRows 2 1 mergedRows_B2 - mergedCols 1 2 mergedCols_C1 - formattedTable 1 1 formattedTable_A1 - formattedTable 1 4 formattedTable_D1 - formattedTable 2 2 formattedTable_B2 - formattedTable 2 3 formattedTable_ÄÖÜäöüß - formattedTable 2 4 äöü€&äöü€& + css:#withHeadAndFoot 1 2 withHeadAndFoot_BH1 + withHeadAndFoot 4 3 withHeadAndFoot_C2 + withHeadAndFoot 6 1 withHeadAndFoot_AF1 + withHeadAndFoot -2 -3 withHeadAndFoot_AF1 + mergedRows 2 1 mergedRows_B2 + mergedCols 1 2 mergedCols_C1 + formattedTable 1 1 formattedTable_A1 + formattedTable 1 4 formattedTable_D1 + formattedTable 2 2 formattedTable_B2 + formattedTable 2 3 formattedTable_ÄÖÜäöüß + formattedTable 2 4 äöü€&äöü€& + +Mixed th and td + [Template] Table Cell Should Be Equal + mixed-th-td 1 1 1.1 (th) + id:mixed-th-td 1 2 1.2 (td) + css:#mixed-th-td 1 3 1.3 (td) + //*[@id="mixed-th-td"] 2 2 2.2 (th) + mixed-th-td 3 2 3.2 (td) + mixed-th-td 4 2 4.2 (th) + mixed-th-td 5 2 5.2 (td) + mixed-th-td 6 2 6.2 (th) + mixed-th-td -1 -1 6.3 (th) + mixed-th-td -1 -2 6.2 (th) + mixed-th-td -1 -3 6.1 (td) + mixed-th-td -6 -3 1.1 (th) + mixed-th-td -6 -2 1.2 (td) + mixed-th-td -6 -1 1.3 (td) Should Give Error Message When Content Not Found In Table Cell Run Keyword And Expect Error - ... Cell in table 'simpleTable' in row #1 and column #2 should have contained text 'simpleTable_B3'. + ... Table 'simpleTable' cell on row 1 and column 2 should have contained text 'simpleTable_B3' but it had 'simpleTable_B1'. ... Table Cell Should Contain simpleTable 1 2 simpleTable_B3 Should Give Error Message When Index Out Of Bounds Run Keyword And Expect Error - ... Cell in table 'simpleTable' in row #10 and column #20 should have contained text 'simpleTable_B3'. + ... Table 'simpleTable' should have had at least 10 rows but had only 3. ... Table Cell Should Contain simpleTable 10 20 simpleTable_B3 + Run Keyword And Expect Error + ... Table 'simpleTable' row 1 should have had at least 20 columns but had only 3. + ... Table Cell Should Contain simpleTable 1 20 simpleTable_B3 -*** Keywords *** -Table Cell Should Be Equal With CSS And XPath Locators - [Arguments] ${tableId} ${row} ${col} ${content} - Run Table Keyword With CSS And XPath Locators - ... Table Cell Should Be Equal ${table id} ${row} ${col} ${content} +Zero is invalid row and column index + Run Keyword And Expect Error + ... ValueError: Both row and column must be non-zero, got row 0 and column 2. + ... Table Cell Should Contain simpleTable 0 2 xxx + Run Keyword And Expect Error + ... ValueError: Both row and column must be non-zero, got row -1 and column 0. + ... Table Cell Should Contain simpleTable -1 0 xxx +*** Keywords *** Table Cell Should Be Equal [Arguments] ${tableId} ${row} ${col} ${content} ${cell}= Get Table Cell ${tableId} ${row} ${col} diff --git a/test/acceptance/keywords/tables/header_should_contain.robot b/test/acceptance/keywords/tables/header_should_contain.robot index d624e989e..b553a71a1 100644 --- a/test/acceptance/keywords/tables/header_should_contain.robot +++ b/test/acceptance/keywords/tables/header_should_contain.robot @@ -3,23 +3,17 @@ Resource table_resource.robot *** Test Cases *** Should Find Text In Header - [Template] Table Header Should Contain With CSS And XPath Locators - tableWithSingleHeader tableWithSingleHeader_A1 - tableWithSingleHeader tableWithSingleHeader_B1 - tableWithTwoHeaders tableWithTwoHeaders_A1 - tableWithTwoHeaders tableWithTwoHeaders_C2 - withHeadAndFoot withHeadAndFoot_AH1 - withHeadAndFoot withHeadAndFoot_CH1 - withHeadAndFoot withHeadAndFoot_AH2 - withHeadAndFoot withHeadAndFoot_BH2 + [Template] Table Header Should Contain + tableWithSingleHeader tableWithSingleHeader_A1 + id:tableWithSingleHeader tableWithSingleHeader_B1 + css:#tableWithTwoHeaders tableWithTwoHeaders_A1 + tableWithTwoHeaders tableWithTwoHeaders_C2 + withHeadAndFoot withHeadAndFoot_AH1 + withHeadAndFoot withHeadAndFoot_CH1 + withHeadAndFoot withHeadAndFoot_AH2 + withHeadAndFoot withHeadAndFoot_BH2 Should Give Error Message When Content Not Found In Table Header Run Keyword And Expect Error - ... Header in table identified by 'withHeadAndFoot' should have contained text 'withHeadAndFoot_B2'. + ... Table 'withHeadAndFoot' header did not contain text 'withHeadAndFoot_B2'. ... Table Header Should Contain withHeadAndFoot withHeadAndFoot_B2 - -*** Keywords *** -Table Header Should Contain With CSS And XPath Locators - [Arguments] ${table id} ${expected} - Run Table Keyword With CSS And XPath Locators Table Header Should Contain - ... ${table id} ${expected} diff --git a/test/acceptance/keywords/tables/row_should_contain.robot b/test/acceptance/keywords/tables/row_should_contain.robot index 544b9a293..af04cefe1 100644 --- a/test/acceptance/keywords/tables/row_should_contain.robot +++ b/test/acceptance/keywords/tables/row_should_contain.robot @@ -1,44 +1,42 @@ *** Settings *** -Documentation Tests table rows content Resource table_resource.robot *** Test Cases *** Should Find Text In Specific Row - [Template] Table Row Should Contain With CSS And XPath Locators - simpleTable 1 simpleTable_A1 - simpleTable 3 simpleTable_C3 - simpleWithNested 1 simpleWithNested_A1 - simpleWithNested 1 nestedTable_A1 - nestedTable 1 nestedTable_A1 - nestedTable 3 nestedTable_C3 + [Template] Table Row Should Contain + simpleTable 1 simpleTable_A1 + id:simpleTable 3 simpleTable_C3 + simpleWithNested 1 simpleWithNested_A1 + simpleWithNested 1 nestedTable_A1 + css:#nestedTable 1 nestedTable_A1 + nestedTable 3 nestedTable_C3 tableWithSingleHeader 1 tableWithSingleHeader_B1 tableWithSingleHeader 2 tableWithSingleHeader_B2 - withHeadAndFoot 2 withHeadAndFoot_B2 - mergedRows 1 mergedRows_A1 - mergedCols 2 mergedCols_B2 - formattedTable 1 formattedTable_A1 - formattedTable 1 formattedTable_B1 - formattedTable 1 formattedTable_C1 - formattedTable 2 formattedTable_A2 - formattedTable 2 formattedTable_B2 - formattedTable 2 formattedTable_ÄÖÜäöüß - formattedTable 2 äöü€&äöü€& + withHeadAndFoot 2 withHeadAndFoot_B2 + //*[@id="mergedRows"] 1 mergedRows_A1 + mergedCols 2 mergedCols_B2 + formattedTable 1 formattedTable_A1 + formattedTable 1 formattedTable_B1 + formattedTable 1 formattedTable_C1 + formattedTable 2 formattedTable_A2 + formattedTable 2 formattedTable_B2 + formattedTable 2 formattedTable_ÄÖÜäöüß + formattedTable 2 äöü€&äöü€& Should Find Text In Specific Row with CSS Specific Mechanics Table Row Should Contain formattedTable 1 formattedTable_D1 Should Give Error Message When Content Not Found In Table Row Run Keyword And Expect Error - ... Row #2 in table identified by 'simpleTable' should have contained text 'simpleTable_B3'. + ... Table 'simpleTable' row 2 did not contain text 'simpleTable_B3'. ... Table Row Should Contain simpleTable 2 simpleTable_B3 Should Give Error Message When Row Number Out Of Bounds Run Keyword And Expect Error - ... Row #20 in table identified by 'simpleTable' should have contained text 'simpleTable_B3'. + ... Table 'simpleTable' row 20 did not contain text 'simpleTable_B3'. ... Table Row Should Contain simpleTable 20 simpleTable_B3 -*** Keywords *** -Table Row Should Contain With CSS And XPath Locators - [Arguments] ${table id} ${row} ${expected} - Run Table Keyword With CSS And XPath Locators Table Row Should Contain - ... ${table id} ${row} ${expected} +Zero is invalid column index + Run Keyword And Expect Error + ... ValueError: Row and column indexes must be non-zero. + ... Table Row Should Contain simpleTable 0 xxx diff --git a/test/acceptance/keywords/tables/table_resource.robot b/test/acceptance/keywords/tables/table_resource.robot index 651b03c47..ca2eb42d3 100644 --- a/test/acceptance/keywords/tables/table_resource.robot +++ b/test/acceptance/keywords/tables/table_resource.robot @@ -1,14 +1,8 @@ *** Settings *** -Documentation Keywords to test tables Resource ../../resource.robot *** Keywords *** Run Table Keyword With CSS And XPath Locators [Arguments] ${keyword} ${table id} @{args} Run Keyword ${keyword} ${table id} @{args} - ${xpath}= Get Table XPath ${table id} - Run Keyword ${keyword} ${xpath} @{args} - -Get Table XPath - [Arguments] ${table id} - [Return] xpath=//table[@id="${table id}"] + Run Keyword ${keyword} //table[@id="${table id}"] @{args} diff --git a/test/acceptance/keywords/tables/table_should_contain.robot b/test/acceptance/keywords/tables/table_should_contain.robot index 6d75030e9..757e4e25e 100644 --- a/test/acceptance/keywords/tables/table_should_contain.robot +++ b/test/acceptance/keywords/tables/table_should_contain.robot @@ -1,51 +1,32 @@ *** Settings *** -Documentation Tests table contents Resource table_resource.robot *** Test Cases *** Should Find Text In Table Content - [Template] Verify Table Contains With CSS And XPath Locators - simpleTable simpleTable_A1 - simpleTable simpleTable_C3 - simpleWithNested simpleWithNested_A1 - simpleWithNested nestedTable_A1 - nestedTable nestedTable_A1 - nestedTable nestedTable_C3 + [Template] Table Should Contain + simpleTable simpleTable_A1 + id:simpleTable simpleTable_C3 + css:#simpleWithNested simpleWithNested_A1 + simpleWithNested nestedTable_A1 + nestedTable nestedTable_A1 + nestedTable nestedTable_C3 tableWithSingleHeader tableWithSingleHeader_B1 tableWithSingleHeader tableWithSingleHeader_B2 - withHeadAndFoot withHeadAndFoot_AH1 - withHeadAndFoot withHeadAndFoot_B2 - withHeadAndFoot withHeadAndFoot_CF1 - mergedRows mergedRows_A1 - mergedCols mergedCols_B2 - formattedTable formattedTable_A1 - formattedTable formattedTable_B1 - formattedTable formattedTable_C1 - formattedTable formattedTable_A2 - formattedTable formattedTable_B2 - formattedTable formattedTable_ÄÖÜäöüß - formattedTable äöü€&äöü€& - -Should Find Text In Table Content with CSS Specific Mechanics - Table Should Contain formattedTable formattedTable_D1 + withHeadAndFoot withHeadAndFoot_AH1 + withHeadAndFoot withHeadAndFoot_B2 + withHeadAndFoot withHeadAndFoot_CF1 + //*[@id="mergedRows"] mergedRows_A1 + mergedCols mergedCols_B2 + formattedTable formattedTable_A1 + formattedTable formattedTable_B1 + formattedTable formattedTable_C1 + formattedTable formattedTable_D1 + formattedTable formattedTable_A2 + formattedTable formattedTable_B2 + formattedTable formattedTable_ÄÖÜäöüß + formattedTable äöü€&äöü€& Should Give Error Message When Content Not Found In Table - [Template] Table Should Contain Fails With CSS And XPath Locators - simpleTable Not here - -*** Keywords *** -Verify Table Contains With CSS And XPath Locators - [Arguments] ${table id} ${expected} - Run Table Keyword With CSS And XPath Locators Table Should Contain - ... ${table id} ${expected} - -Table Should Contain Fails With CSS And XPath Locators - [Arguments] ${table id} ${expected} - Run Table Keyword With CSS And XPath Locators Table Should Contain Fails - ... ${table id} ${expected} - -Table Should Contain Fails - [Arguments] ${locator} ${expected} - ${err}= Set Variable - ... Table identified by '${locator}' should have contained text '${expected}'. - Run Keyword And Expect Error ${err} Table Should Contain ${locator} ${expected} + Run Keyword And Expect Error + ... Table 'simpleTable' did not contain text 'Not here'. + ... Table Should Contain simpleTable Not here diff --git a/test/resources/html/tables/tables.html b/test/resources/html/tables/tables.html index 60864dd4f..77cc48983 100644 --- a/test/resources/html/tables/tables.html +++ b/test/resources/html/tables/tables.html @@ -166,6 +166,17 @@

Table with thead, tfoot and tbody sections

+ +

Table with mixed th and td

+ + + + + + + +
1.1 (th)1.2 (td)1.3 (td)
2.1 (td)2.2 (th)2.3 (td)
3.1 (td)3.2 (td)3.3 (th)
4.1 (th)4.2 (th)4.3 (td)
5.1 (th)5.2 (td)5.3 (th)
6.1 (td)6.2 (th)6.3 (th)
+

Table With Merged Cells In a Row

diff --git a/test/unit/locators/test_tableelementfinder.py b/test/unit/locators/test_tableelementfinder.py index ceaf638be..e6ec6a0d1 100644 --- a/test/unit/locators/test_tableelementfinder.py +++ b/test/unit/locators/test_tableelementfinder.py @@ -1,6 +1,6 @@ import unittest -from mockito import mock, verify, when, unstub +from mockito import mock, when, unstub from SeleniumLibrary.locators.tableelementfinder import TableElementFinder @@ -15,41 +15,22 @@ def setUp(self): def tearDown(self): unstub() - def test_find_by_col(self): - element = mock() - xpath = ['//tr//*[self::td or self::th][1]'] - when(self.finder)._search_in_locators('id:table', xpath, - 'content').thenReturn(element) - self.finder.find_by_col('id:table', 1, 'content') + def test_find_by_column(self): + xpath = '//tr//*[self::td or self::th][1]' + when(self.finder)._find('id:table', xpath, 'content').thenReturn(mock()) + self.finder.find_by_column('id:table', 1, 'content') - xpath = ['//tbody/tr/td[position()=last()-(2-1)]', - '//tbody/tr/td[position()=last()-(2-1)]'] - when(self.finder)._search_in_locators('id:table', xpath, - 'content').thenReturn(element) - self.finder.find_by_col('id:table', 1, 'content') + def test_find_by_column_with_negative_index(self): + xpath = '//tr//*[self::td or self::th][position()=last()]' + when(self.finder)._find('id:table', xpath, 'content').thenReturn(mock()) + self.finder.find_by_column('id:table', -1, 'content') def test_find_by_row(self): - element = mock() - xpath = ['//tr[2]//*'] - when(self.finder)._search_in_locators('xpath=//table', xpath, - 'content').thenReturn(element) + xpath = '//tr[2]' + when(self.finder)._find('xpath=//table', xpath, 'content').thenReturn(mock()) self.finder.find_by_row('xpath=//table', 2, 'content') - xpath = ['//tbody/tr[position()=last()-(3-1)]'] - when(self.finder)._search_in_locators('xpath=//table', xpath, - 'content').thenReturn(element) + def test_find_by_row_with_negative_index(self): + xpath = '//tr[position()=last()-2]' + when(self.finder)._find('xpath=//table', xpath, 'content').thenReturn(mock()) self.finder.find_by_row('xpath=//table', -3, 'content') - - def test_by_search_in_locators(self): - xpath = ['//th'] - table = mock() - element1 = mock() - element2 = mock() - element1.text = 'not here' - element2.text = 'content' - table_elements = [element1, element2] - when(self.ctx._element_finder).find( - 'css=table', None, True, True, None).thenReturn(table) - when(self.ctx._element_finder).find( - xpath[0], None, False, False, table).thenReturn(table_elements) - self.finder._search_in_locators('css=table', xpath, 'content')