![Timur Sufiev](/assets/img/avatar_default.png)
Instead of this match them by action <a> tag's id, which is composed: * from table name, fixed part and action name for table-level actions and * from row id, fixed part and action name for row-level actions. Doing so may make action names in page objects less readable as they have to be the same as real object name (which are rather terse). Implements blueprint: integration-tests-hardening Change-Id: I3f92ef4cfd098d080199350cbf5e6061aa050907
247 lines
8.7 KiB
Python
247 lines
8.7 KiB
Python
# 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.
|
|
|
|
|
|
from selenium.webdriver.common import by
|
|
|
|
from openstack_dashboard.test.integration_tests.regions import baseregion
|
|
from openstack_dashboard.test.integration_tests.regions import menus
|
|
|
|
|
|
class RowRegion(baseregion.BaseRegion):
|
|
"""Classic table row."""
|
|
|
|
_cell_locator = (by.By.CSS_SELECTOR, 'td.normal_column')
|
|
|
|
@property
|
|
def cells(self):
|
|
return self._get_elements(*self._cell_locator)
|
|
|
|
|
|
class BaseActionRowRegion(RowRegion):
|
|
"""Base class for creating ActionRow class derivative."""
|
|
|
|
_row_checkbox_locator = (by.By.CSS_SELECTOR, 'td > input')
|
|
|
|
def mark(self):
|
|
chck_box = self._get_element(*self._row_checkbox_locator)
|
|
chck_box.click()
|
|
|
|
|
|
class BtnActionRowRegion(BaseActionRowRegion):
|
|
"""Row with buttons in action column."""
|
|
|
|
_action_locator = (by.By.CSS_SELECTOR, 'td.actions_column > button')
|
|
|
|
def __init__(self, driver, conf, src_elem, action_name):
|
|
super(BtnActionRowRegion, self).__init__(driver, conf, src_elem)
|
|
self.action_name = action_name
|
|
self._action_id_pattern = ("%s__action_%%s" %
|
|
src_elem.get_attribute('id'))
|
|
self._init_action()
|
|
|
|
def _init_action(self):
|
|
self._init_dynamic_property(self.action_name, self._get_action,
|
|
self._action_id_pattern)
|
|
|
|
def _get_action(self):
|
|
return self._get_element(*self._action_locator)
|
|
|
|
@property
|
|
def action(self):
|
|
return self._get_action()
|
|
|
|
|
|
class ComplexActionRowRegion(BaseActionRowRegion):
|
|
"""Row with button and select box in action column."""
|
|
|
|
_primary_action_locator = (by.By.CSS_SELECTOR,
|
|
'td.actions_column > div.btn-group > *.btn')
|
|
_secondary_actions_dropdown_locator = (by.By.CSS_SELECTOR,
|
|
'div.btn-group')
|
|
|
|
PRIMARY_ACTION = "primary_action"
|
|
SECONDARY_ACTIONS = "secondary_actions"
|
|
|
|
ACTIONS_ERROR_MSG = ("Actions must be supplied in dictionary:"
|
|
" {%s: 'action_name', '%s': ('action_name',...)}"
|
|
% (PRIMARY_ACTION, SECONDARY_ACTIONS))
|
|
|
|
def __init__(self, driver, conf, src_elem, action_names):
|
|
super(ComplexActionRowRegion, self).__init__(driver, conf, src_elem)
|
|
try:
|
|
self.primary_action_name = action_names[self.PRIMARY_ACTION]
|
|
self.secondary_action_names = action_names[self.SECONDARY_ACTIONS]
|
|
self._action_id_pattern = ("%s__action_%%s" %
|
|
src_elem.get_attribute('id'))
|
|
self._init_actions()
|
|
except (TypeError, KeyError):
|
|
raise AttributeError(self.ACTIONS_ERROR_MSG)
|
|
|
|
def _init_actions(self):
|
|
self._init_dynamic_property(self.primary_action_name,
|
|
self._get_primary_action,
|
|
self._action_id_pattern)
|
|
self._init_dynamic_properties(self.secondary_action_names,
|
|
self._get_secondary_actions,
|
|
self._action_id_pattern)
|
|
|
|
def _get_primary_action(self):
|
|
return self._get_element(*self._primary_action_locator)
|
|
|
|
def _get_secondary_actions(self):
|
|
src_elem = self._get_element(*self._secondary_actions_dropdown_locator)
|
|
dropdown = menus.DropDownMenuRegion(self.driver, self.conf, src_elem)
|
|
return dropdown.menu_items
|
|
|
|
@property
|
|
def primary_action(self):
|
|
return self._get_primary_action()
|
|
|
|
@property
|
|
def secondary_actions(self):
|
|
return self._get_secondary_actions()
|
|
|
|
|
|
class BasicTableRegion(baseregion.BaseRegion):
|
|
"""Basic class representing table object."""
|
|
|
|
_heading_locator = (by.By.CSS_SELECTOR, 'h3.table_title')
|
|
_columns_names_locator = (by.By.CSS_SELECTOR, 'thead > tr > th')
|
|
_footer_locator = (by.By.CSS_SELECTOR, 'tfoot > tr > td > span')
|
|
_rows_locator = (by.By.CSS_SELECTOR, 'tbody > tr')
|
|
_empty_table_locator = (by.By.CSS_SELECTOR, 'tbody > tr.empty')
|
|
_search_field_locator = (by.By.CSS_SELECTOR,
|
|
'div.table_search.client > input')
|
|
_search_button_locator = (by.By.CSS_SELECTOR,
|
|
'div.table_search.client > button')
|
|
|
|
@property
|
|
def heading(self):
|
|
return self._get_element(*self._heading_locator)
|
|
|
|
@property
|
|
def rows(self):
|
|
if self._is_element_present(*self._empty_table_locator):
|
|
return []
|
|
else:
|
|
return self._get_rows()
|
|
|
|
@property
|
|
def column_names(self):
|
|
return self._get_elements(*self._columns_names_locator)
|
|
|
|
@property
|
|
def footer(self):
|
|
return self._get_element(*self._footer_locator)
|
|
|
|
def filter(self, value):
|
|
self._set_search_field(value)
|
|
self._click_search_btn()
|
|
|
|
def get_row(self, column_index, text, exact_match=True):
|
|
"""Get row that contains specified text in specified column.
|
|
|
|
In case exact_match is set to True, text contained in row must equal
|
|
searched text, otherwise occurrence of searched text in the column
|
|
text will result in row match.
|
|
"""
|
|
def get_text(element):
|
|
text = element.get_attribute('data-selenium')
|
|
return text or element.text
|
|
|
|
for row in self.rows:
|
|
if exact_match and text == get_text(row.cells[column_index]):
|
|
return row
|
|
if not exact_match and text in get_text(row.cells[column_index]):
|
|
return row
|
|
return None
|
|
|
|
def _set_search_field(self, value):
|
|
srch_field = self._get_element(*self._search_field_locator)
|
|
srch_field.send_keys(value)
|
|
|
|
def _click_search_btn(self):
|
|
btn = self._get_element(*self._search_button_locator)
|
|
btn.click()
|
|
|
|
def _get_rows(self):
|
|
rows = []
|
|
for elem in self._get_elements(*self._rows_locator):
|
|
rows.append(RowRegion(self.driver, self.conf, elem))
|
|
|
|
|
|
class ActionsTableRegion(BasicTableRegion):
|
|
"""Base class for creating derivative of BasicTableRegion that
|
|
has some actions.
|
|
"""
|
|
|
|
_actions_locator = (by.By.CSS_SELECTOR, 'div.table_actions > button,'
|
|
' div.table_actions > a')
|
|
|
|
# private methods
|
|
def __init__(self, driver, conf, src_elm, table_name, action_names):
|
|
super(ActionsTableRegion, self).__init__(driver, conf, src_elm)
|
|
self._action_id_pattern = "%s__action_%%s" % table_name
|
|
self.action_names = action_names
|
|
self._init_actions()
|
|
|
|
# protected methods
|
|
def _init_actions(self):
|
|
"""Create new methods that corresponds to picking table's
|
|
action buttons.
|
|
"""
|
|
self._init_dynamic_properties(self.action_names, self._get_actions,
|
|
self._action_id_pattern)
|
|
|
|
def _get_actions(self):
|
|
return self._get_elements(*self._actions_locator)
|
|
|
|
# properties
|
|
@property
|
|
def actions(self):
|
|
return self._get_actions()
|
|
|
|
|
|
class SimpleActionsTableRegion(ActionsTableRegion):
|
|
"""Table which rows has buttons in action column."""
|
|
|
|
def __init__(self, driver, conf, src_elm, table_name, action_names,
|
|
row_action_name):
|
|
super(SimpleActionsTableRegion, self).__init__(
|
|
driver, conf, src_elm, table_name, action_names)
|
|
self.row_action_name = row_action_name
|
|
|
|
def _get_rows(self):
|
|
rows = []
|
|
for elem in self._get_elements(*self._rows_locator):
|
|
rows.append(BtnActionRowRegion(self.driver, self.conf, elem,
|
|
self.row_action_name))
|
|
return rows
|
|
|
|
|
|
class ComplexActionTableRegion(ActionsTableRegion):
|
|
"""Table which has button and selectbox in the action column."""
|
|
|
|
def __init__(self, driver, conf, src_elm, table_name,
|
|
action_names, row_action_names):
|
|
super(ComplexActionTableRegion, self).__init__(
|
|
driver, conf, src_elm, table_name, action_names)
|
|
self.row_action_names = row_action_names
|
|
|
|
def _get_rows(self):
|
|
rows = []
|
|
for elem in self._get_elements(*self._rows_locator):
|
|
rows.append(ComplexActionRowRegion(self.driver, self.conf, elem,
|
|
self.row_action_names))
|
|
return rows
|