horizon/openstack_dashboard/test/integration_tests/regions/tables.py
Tomas Novacik 7b16bbf920 Add test_sahara_image_registry
Add simple test for page under /Project/Data Processing/Image Registry,
that registers and unregisters an image in the Sahara registry.

Infrastructure changes needed by the test:
 - new page object with basic handling of the Image Registry page;
 - new ssh_user config option with the cloud-init username for the
   image (named after the corresponding tempest option);
 - new parameter in get_row() table method for exact match;
 - add "wait-until-active" method for the Image page;
 - enable sahara service by default in horizon.conf.

Partially implements blueprint: selenium-integration-testing
Co-Authored-By: Luigi Toscano <ltoscano@redhat.com>

Change-Id: I1e389f0baff655f8f06a0a6cbb4a10b9a68dd444
2015-03-05 11:36:00 +01:00

232 lines
8.1 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._init_action()
def _init_action(self):
self._init_dynamic_property(self.action_name, self._get_action)
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._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._init_dynamic_properties(self.secondary_action_names,
self._get_secondary_actions)
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.
"""
for row in self.rows:
if exact_match and text == row.cells[column_index].text:
return row
if not exact_match and text in row.cells[column_index].text:
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, action_names):
super(ActionsTableRegion, self).__init__(driver, conf, src_elm)
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)
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, action_names, row_action_name):
super(SimpleActionsTableRegion, self).__init__(driver, conf, src_elm,
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, action_names, row_action_names):
super(ComplexActionTableRegion, self).__init__(driver, conf, src_elm,
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