Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions src/Selenium2Library/keywords/_tableelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,28 @@ def get_table_cell(self, table_locator, row, column, loglevel='INFO'):
"""Returns the content from a table cell.

Row and column number start from 1. Header and footer rows are
included in the count. This means that also 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`.
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`.
"""
row = int(row)
row_index = row - 1
row_index = row
if row > 0: row_index = row - 1
column = int(column)
column_index = column - 1
column_index = column
if column > 0: column_index = column - 1
table = self._table_element_finder.find(self._current_browser(), table_locator)
if table is not None:
rows = table.find_elements_by_xpath("./thead/tr")
if row_index >= len(rows): rows.extend(table.find_elements_by_xpath("./tbody/tr"))
if row_index >= len(rows): rows.extend(table.find_elements_by_xpath("./tfoot/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): columns.extend(rows[row_index].find_elements_by_tag_name('td'))
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.log_source(loglevel)
Expand Down Expand Up @@ -69,8 +74,9 @@ def table_cell_should_contain(self, table_locator, row, column, expected, loglev
def table_column_should_contain(self, table_locator, col, expected, loglevel='INFO'):
"""Verifies that a specific column contains `expected`.

The first leftmost column is column number 1. If the table
contains cells that span multiple columns, those merged cells
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".
Expand Down Expand Up @@ -126,10 +132,11 @@ def table_header_should_contain(self, table_locator, expected, loglevel='INFO'):
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. 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
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
Expand Down
24 changes: 19 additions & 5 deletions src/Selenium2Library/locators/tableelementfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ def __init__(self, element_finder=None):
('css', 'header'): [' th'],
('css', 'footer'): [' tfoot td'],
('css', 'row'): [' tr:nth-child(%s)'],
('css', 'last-row'): [' tr:nth-last-child(%s)'],
('css', 'col'): [' tr td:nth-child(%s)', ' tr th:nth-child(%s)'],
('css', 'last-col'): [' tr td:nth-last-child(%s)', ' tr th:nth-last-child(%s)'],

('jquery', 'default'): [''],
('jquery', 'content'): [''],
Expand All @@ -36,7 +38,9 @@ def __init__(self, element_finder=None):
('xpath', 'header'): ['//th'],
('xpath', 'footer'): ['//tfoot//td'],
('xpath', 'row'): ['//tr[%s]//*'],
('xpath', 'col'): ['//tr//*[self::td or self::th][%s]']
('xpath', 'last-row'): [' //tbody/tr[position()=last()-(%s-1)]'],
('xpath', 'col'): ['//tr//*[self::td or self::th][%s]'],
('xpath', 'last-col'): [' //tbody/tr/td[position()=last()-(%s-1)]', ' //tbody/tr/td[position()=last()-(%s-1)]']
};

def find(self, browser, table_locator):
Expand All @@ -55,13 +59,23 @@ def find_by_footer(self, browser, table_locator, content):
locators = self._parse_table_locator(table_locator, 'footer')
return self._search_in_locators(browser, locators, content)

def find_by_row(self, browser, table_locator, col, content):
locators = self._parse_table_locator(table_locator, 'row')
locators = [locator % str(col) for locator in locators]
def find_by_row(self, browser, table_locator, row, content):
location_method = "row"
row = str(row)
if row[0] == "-":
row = row[1:]
location_method = "last-row"
locators = self._parse_table_locator(table_locator, location_method)
locators = [locator % str(row) for locator in locators]
return self._search_in_locators(browser, locators, content)

def find_by_col(self, browser, table_locator, col, content):
locators = self._parse_table_locator(table_locator, 'col')
location_method = "col"
col = str(col)
if col[0] == "-":
col = col[1:]
location_method = "last-col"
locators = self._parse_table_locator(table_locator, location_method)
locators = [locator % str(col) for locator in locators]
return self._search_in_locators(browser, locators, content)

Expand Down
2 changes: 1 addition & 1 deletion test/acceptance/create_webdriver.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Library Collections

*Test Cases*
Create Webdriver Creates Functioning WebDriver
[Documentation] LOG 2:1 INFO REGEXP: Creating an instance of the \\w+ WebDriver LOG 2:3 DEBUG REGEXP: Created \\w+ WebDriver instance with session id (\\w|-)+
[Documentation] LOG 2:1 INFO REGEXP: Creating an instance of the \\w+ WebDriver LOG 2:4 DEBUG REGEXP: Created \\w+ WebDriver instance with session id (\\w|-)+
[Setup] Set Driver Variables
Create Webdriver ${DRIVER_NAME} kwargs=${KWARGS}
Go To ${FRONT PAGE}
Expand Down
22 changes: 11 additions & 11 deletions test/acceptance/keywords/content_assertions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@ Resource ../resource.txt

*** Test Cases ***
Location Should Be
[Documentation] LOG 2:2 Current location is '${FRONT PAGE}'.
[Documentation] LOG 2:3 Current location is '${FRONT PAGE}'.
Location Should Be ${FRONT PAGE}
Run Keyword And Expect Error Location should have been 'non existing' but was '${FRONT PAGE}' Location Should Be non existing

Location Should Contain
[Documentation] LOG 2:2 Current location contains 'html'.
[Documentation] LOG 2:3 Current location contains 'html'.
Location Should Contain html
Run Keyword And Expect Error Location should have contained 'not a location' but it was '${FRONT PAGE}'. Location Should Contain not a location

Title Should Be
[Documentation] LOG 2:2 Page title is '(root)/index.html'.
[Documentation] LOG 2:3 Page title is '(root)/index.html'.
Title Should Be (root)/index.html
Run Keyword And Expect Error Title should have been 'not a title' but was '(root)/index.html' Title Should Be not a title

Page Should Contain
[Documentation] LOG 2:3 Current page contains text 'needle'. LOG 4.1:6 REGEXP: (?i)<html .*</html>
[Documentation] LOG 2:5 Current page contains text 'needle'. LOG 4.1:10 REGEXP: (?i)<html .*</html>
Page Should Contain needle
Page Should Contain This is the haystack
Run Keyword And Expect Error Page should have contained text 'non existing text' but did not Page Should Contain non existing text

Page Should Contain With Custom Log Level
[Documentation] LOG 2.1:6 DEBUG REGEXP: (?i)<html .*</html>
[Documentation] LOG 2.1:10 DEBUG REGEXP: (?i)<html .*</html>
Run Keyword And Expect Error Page should have contained text 'non existing text' but did not Page Should Contain non existing text DEBUG

Page Should Contain With Disabling Source Logging
Expand All @@ -41,12 +41,12 @@ Page Should Contain With Frames
Page Should Contain You're looking at right.

Page Should Not Contain
[Documentation] LOG 2:5 Current page does not contain text 'non existing text'. LOG 3.1:4 REGEXP: (?i)<html .*</html>
[Documentation] LOG 2:8 Current page does not contain text 'non existing text'. LOG 3.1:7 REGEXP: (?i)<html .*</html>
Page Should Not Contain non existing text
Run Keyword And Expect Error Page should not have contained text 'needle' Page Should Not Contain needle

Page Should Not Contain With Custom Log Level
[Documentation] LOG 2.1:4 DEBUG REGEXP: (?i)<html .*</html>
[Documentation] LOG 2.1:7 DEBUG REGEXP: (?i)<html .*</html>
Run Keyword And Expect Error Page should not have contained text 'needle' Page Should Not Contain needle DEBUG

Page Should Not Contain With Disabling Source Logging
Expand Down Expand Up @@ -103,14 +103,14 @@ Element Should Not Be Visible
Run Keyword And Expect Error The element 'i_am_visible' should not be visible, but it is. Element Should Not Be Visible i_am_visible

Page Should Contain Checkbox
[Documentation] LOG 2:3 Current page contains checkbox 'can_send_email'.
[Documentation] LOG 2:5 Current page contains checkbox 'can_send_email'.
[Setup] Go To Page "forms/prefilled_email_form.html"
Page Should Contain Checkbox can_send_email
Page Should Contain Checkbox xpath=//input[@type='checkbox' and @name='can_send_sms']
Run Keyword And Expect Error Page should have contained checkbox 'non-existing' but did not Page Should Contain Checkbox non-existing

Page Should Not Contain Checkbox
[Documentation] LOG 2:3 Current page does not contain checkbox 'non-existing'.
[Documentation] LOG 2:5 Current page does not contain checkbox 'non-existing'.
[Setup] Go To Page "forms/prefilled_email_form.html"
Page Should Not Contain Checkbox non-existing
Run Keyword And Expect Error Page should not have contained checkbox 'can_send_email' Page Should Not Contain Checkbox can_send_email
Expand Down Expand Up @@ -169,15 +169,15 @@ Page Should Not Contain Text Field
Run Keyword And Expect Error Page should not have contained text field 'name' Page Should Not Contain Text Field name

TextField Should Contain
[Documentation] LOG 2:4 Text field 'name' contains text ''.
[Documentation] LOG 2:7 Text field 'name' contains text ''.
[Setup] Go To Page "forms/email_form.html"
TextField Should contain name ${EMPTY}
Input Text name my name
TextField Should contain name my name
Run Keyword And Expect Error Text field 'name' should have contained text 'non-existing' but it contained 'my name' TextField Should contain name non-existing

TextField Value Should Be
[Documentation] LOG 2:4 Content of text field 'name' is ''.
[Documentation] LOG 2:7 Content of text field 'name' is ''.
[Setup] Go To Page "forms/email_form.html"
textfield Value Should Be name ${EMPTY}
Input Text name my name
Expand Down
9 changes: 5 additions & 4 deletions test/acceptance/keywords/forms_and_buttons.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ Click button created with <button> by tag content
Verify Location Is "${FORM SUBMITTED}"

Choose File
[Setup] Navigate To File Upload Form And Create Temp File To Upload
Choose File file_to_upload ${CURDIR}${/}temp.txt
Text Field Value Should Be file_to_upload ${CURDIR}${/}temp.txt
[Teardown] Remove File ${CURDIR}${/}temp.txt
[Setup] Navigate To File Upload Form And Create Temp File To Upload
Choose File file_to_upload ${TEMPDIR}${/}temp.txt
${dep_browser}= Set Variable If '${BROWSER}'.lower() == 'ff' or '${BROWSER}'.lower() == 'firefox' temp.txt C:\\fakepath\\temp.txt #Needs to be checked in Windows and OS X
Textfield Value Should Be name= file_to_upload ${dep_browser}
[Teardown] Remove File ${TEMPDIR}${/}temp.txt

Click Image With Submit Type Images
[Setup] Go To Page "forms/form_with_image_submit.html"
Expand Down
2 changes: 1 addition & 1 deletion test/acceptance/keywords/screenshots.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Suite Setup Go To Page "links.html"
* Test Cases *

Capture page screenshot to default location
[Documentation] LOG 2:2 REGEXP: </td></tr><tr><td colspan="3"><a href="selenium-screenshot-\\d.png"><img src="selenium-screenshot-\\d.png" width="800px"></a>
[Documentation] LOG 2:3 REGEXP: </td></tr><tr><td colspan="3"><a href="selenium-screenshot-\\d.png"><img src="selenium-screenshot-\\d.png" width="800px"></a>
[Setup] Remove Files ${OUTPUTDIR}/selenium-screenshot-*.png
Capture Page Screenshot
${count} = Count Files In Directory ${OUTPUTDIR} selenium-screenshot-*.png
Expand Down
23 changes: 23 additions & 0 deletions test/acceptance/keywords/tables/negative_indexes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
*** Settings ***
Resource table_resource.txt
Documentation Tests negative indexes in Robot keywords

*** Test Cases ***
Test negative index for CSS strategy in 'Table Row Should Contain'
Table Row Should Contain tableWithSingleHeader -1 tableWithSingleHeader_A3 tableWithSingleHeader_B3 tableWithSingleHeader_C3

Test negative index for XPath strategy in 'Table Row Should Contain'
Table Row Should Contain xpath=//*[@id='tableWithSingleHeader'] -1 tableWithSingleHeader_A3 tableWithSingleHeader_B3 tableWithSingleHeader_C3

Test negative index for CSS strategy in 'Table Column Should Contain'
Table Column Should Contain tableWithSingleHeader -1 tableWithSingleHeader_C2

Test negative index for XPath strategy in 'Table Column Should Contain'
Table Column Should Contain xpath=//*[@id='tableWithSingleHeader'] -1 tableWithSingleHeader_C2

Test negative index for XPath strategy in 'Table Cell Should Contain'
Table Cell Should Contain simpleTable -1 -2 simpleTable_B3

Test negative index for CSS strategy in 'Table Cell Should Contain'
Table Cell Should Contain xpath=//*[@name='simpleTableName'] -1 -2 simpleTableName_B3

2 changes: 2 additions & 0 deletions test/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def process_output(args):
rebot = 'rebot' if os.sep == '/' else 'rebot.bat'
rebot_cmd = [rebot] + [ arg % ARG_VALUES for arg in REBOT_ARGS ] + args + \
[os.path.join(ARG_VALUES['outdir'], 'output.xml') ]
print ''
print 'Starting output processing with command:\n' + ' '.join(rebot_cmd)
rc = call(rebot_cmd, env=os.environ)
if rc == 0:
print 'All critical tests passed'
Expand Down