Integration tests no longer use form's fields ordering for matching

Relying on suggestion that some predefined list of field names in test
will always be the same in actual forms rendered by Horizon is
perilous. It leads to a test failure every time the order of fields in
some form being tested changes or a new field appears at the beginning
of the form. Tests which are using 'name' attribute for matching
predefined fields to the actual form fields are much more durable
since field names change less frequently.

Closes-Bug: #1467950
Related-Bug: #1456294
Related-Bug: #1447432
Implements blueprint: integration-tests-hardening

Change-Id: Ia39c003a628f5abbb73ff824329b2a31a0b6e179
This commit is contained in:
Timur Sufiev 2015-08-19 18:18:31 +03:00
parent ce53171d18
commit 59717143bc
8 changed files with 51 additions and 32 deletions

View File

@ -30,9 +30,8 @@ class FlavorsPage(basepage.BaseNavigationPage):
"modify_access", "update_metadata", "delete_flavor")
}
CREATE_FLAVOR_FORM_FIELDS = (("name", "id_", "vcpus", "ram",
"root_disk", "ephemeral_disk",
"swap_disk"),
CREATE_FLAVOR_FORM_FIELDS = (("name", "flavor_id", "vcpus", "memory_mb",
"disk_gb", "eph_gb", "swap_mb"),
("all_projects", "selected_projects"))
def __init__(self, driver, conf):
@ -65,12 +64,12 @@ class FlavorsPage(basepage.BaseNavigationPage):
self.flavors_table.create_flavor.click()
self.create_flavor_form.name.text = name
if id_ is not None:
self.create_flavor_form.id_.text = id_
self.create_flavor_form.flavor_id.text = id_
self.create_flavor_form.vcpus.value = vcpus
self.create_flavor_form.ram.value = ram
self.create_flavor_form.root_disk.value = root_disk
self.create_flavor_form.ephemeral_disk.value = ephemeral_disk
self.create_flavor_form.swap_disk.value = swap_disk
self.create_flavor_form.memory_mb.value = ram
self.create_flavor_form.disk_gb.value = root_disk
self.create_flavor_form.eph_gb.value = ephemeral_disk
self.create_flavor_form.swap_mb.value = swap_disk
self.create_flavor_form.submit.click()
self._wait_till_spinner_disappears()

View File

@ -32,7 +32,7 @@ class UsersPage(basepage.BaseNavigationPage):
}
CREATE_USER_FORM_FIELDS = ("name", "email", "password",
"confirm_password", "project", "role")
"confirm_password", "project", "role_id")
def __init__(self, driver, conf):
super(UsersPage, self).__init__(driver, conf)
@ -69,7 +69,7 @@ class UsersPage(basepage.BaseNavigationPage):
self.create_user_form.password.text = password
self.create_user_form.confirm_password.text = password
self.create_user_form.project.text = project
self.create_user_form.role.text = role
self.create_user_form.role_id.text = role
self.create_user_form.submit.click()
self._wait_till_spinner_disappears()

View File

@ -36,10 +36,10 @@ class ImagesPage(basepage.BaseNavigationPage):
}
CREATE_IMAGE_FORM_FIELDS = (
"name", "description", "image_source", "image_location",
"name", "description", "source_type", "image_url",
"image_file", "kernel", "ramdisk",
"format", "architecture", "minimum_disk",
"minimum_ram", "public", "protected"
"disk_format", "architecture", "minimum_disk",
"minimum_ram", "is_public", "protected"
)
def __init__(self, driver, conf):
@ -69,7 +69,7 @@ class ImagesPage(basepage.BaseNavigationPage):
return forms.BaseFormRegion(self.driver, self.conf, None)
def create_image(self, name, description=None,
image_source=DEFAULT_IMAGE_SOURCE,
image_source_type=DEFAULT_IMAGE_SOURCE,
location=None, image_file=None,
image_format=DEFAULT_IMAGE_FORMAT,
is_public=DEFAULT_ACCESSIBILITY,
@ -78,18 +78,18 @@ class ImagesPage(basepage.BaseNavigationPage):
self.create_image_form.name.text = name
if description is not None:
self.create_image_form.description.text = description
self.create_image_form.image_source.value = image_source
if image_source == 'url':
self.create_image_form.source_type.value = image_source_type
if image_source_type == 'url':
if location is None:
self.create_image_form.image_location.text = \
self.create_image_form.image_url.text = \
self.conf.image.http_image
else:
self.create_image_form.location.text = location
self.create_image_form.image_url.text = location
else:
self.create_image_form.image_file.choose(image_file)
self.create_image_form.format.value = image_format
self.create_image_form.disk_format.value = image_format
if is_public:
self.create_image_form.public.mark()
self.create_image_form.is_public.mark()
if is_protected:
self.create_image_form.protected.mark()
self.create_image_form.submit.click()

View File

@ -21,7 +21,7 @@ class ChangepasswordPage(basepage.BaseNavigationPage):
_password_form_locator = (by.By.ID, 'change_password_modal')
CHANGE_PASSWORD_FORM_FIELDS = ("current_password", "new_password",
"confirm_new_password")
"confirm_password")
@property
def password_form(self):
@ -32,7 +32,7 @@ class ChangepasswordPage(basepage.BaseNavigationPage):
def change_password(self, current, new):
self.password_form.current_password.text = current
self.password_form.new_password.text = new
self.password_form.confirm_new_password.text = new
self.password_form.confirm_password.text = new
self.password_form.submit.click()
def reset_to_default_password(self, current):

View File

@ -30,7 +30,8 @@ class UsersettingsPage(basepage.BaseNavigationPage):
"loglines": DEFAULT_LOGLINES
}
SETTINGS_FORM_FIELDS = ("language", "timezone", "pagesize", "loglines")
SETTINGS_FORM_FIELDS = (
"language", "timezone", "pagesize", "instance_log_length")
_settings_form_locator = (by.By.ID, 'user_settings_modal')
_change_password_tab_locator = (by.By.CSS_SELECTOR,
@ -67,7 +68,7 @@ class UsersettingsPage(basepage.BaseNavigationPage):
self.settings_form.submit.click()
def change_loglines(self, lines=DEFAULT_LOGLINES):
self.settings_form.loglines.value = lines
self.settings_form.instance_log_length.value = lines
self.settings_form.submit.click()
def return_to_default_settings(self):

View File

@ -65,17 +65,21 @@ class BaseRegion(basewebobject.BaseWebObject):
class _DynamicProperty(object):
"""Serves as new property holder."""
def __init__(self, method, index=None):
def __init__(self, method, index=None, name=None):
"""In case object was created with index != None,
it is assumed that the result of self.method should be tuple()
and just certain index should be returned
"""
self.method = method
self.index = index
self.name = name
def __call__(self, *args, **kwargs):
result = self.method()
return result if self.index is None else result[self.index]
if isinstance(result, dict):
return result if self.name is None else result[self.name]
else:
return result if self.index is None else result[self.index]
def _init_dynamic_properties(self, new_attr_names, method):
"""Create new object's 'properties' at runtime."""
@ -93,7 +97,8 @@ class BaseRegion(basewebobject.BaseWebObject):
"The new property could not be "
"created." % (self.__class__.__name__,
new_attr_name))
new_method = self.__class__._DynamicProperty(method, index)
new_method = self.__class__._DynamicProperty(method, index,
new_attr_name)
inst_method = types.MethodType(new_method, self)
self._dynamic_properties[new_attr_name] = inst_method

View File

@ -64,6 +64,10 @@ class BaseFormFieldRegion(baseregion.BaseRegion):
def element(self):
return self._get_element(*self._element_locator)
@property
def name(self):
return self.element.get_attribute('name')
def is_required(self):
classes = self.driver.get_attribute('class')
return 'required' in classes
@ -205,6 +209,10 @@ class SelectFormFieldRegion(BaseFormFieldRegion):
results.append(option.get_attribute('value'))
return results
@property
def name(self):
return self.element._el.get_attribute('name')
@property
def text(self):
return self.element.first_selected_option.text
@ -254,6 +262,7 @@ class FormRegion(BaseFormRegion):
_header_locator = (by.By.CSS_SELECTOR, 'div.modal-header > h3')
_side_info_locator = (by.By.CSS_SELECTOR, 'div.right')
_fields_locator = (by.By.CSS_SELECTOR, 'fieldset > div.form-group')
_input_locator = (by.By.CSS_SELECTOR, 'input,select,textarea')
# private methods
def __init__(self, driver, conf, src_elem, form_field_names):
@ -268,12 +277,13 @@ class FormRegion(BaseFormRegion):
def _get_form_fields(self):
fields_els = self._get_elements(*self._fields_locator)
form_fields = []
form_fields = {}
try:
self._turn_off_implicit_wait()
for elem in fields_els:
field_factory = FieldFactory(self.driver, self.conf, elem)
form_fields.append(field_factory.make_form_field())
field = field_factory.make_form_field()
form_fields[field.name] = field
finally:
self._turn_on_implicit_wait()
return form_fields
@ -350,8 +360,12 @@ class TabbedFormRegion(FormRegion):
def __call__(self, *args, **kwargs):
self.switch_to_tab(self.tab_index)
return [field for field in self.get_fields()
if field.is_displayed()]
fields = self.get_fields()
if isinstance(fields, dict):
return dict([(key, field) for (key, field)
in fields.iteritems() if field.is_displayed()])
else:
return [field for field in fields if field.is_displayed()]
@property
def tabs(self):

View File

@ -19,7 +19,7 @@ class TestUserSettings(helpers.TestCase):
language = self.settings_page.settings_form.language.value
timezone = self.settings_page.settings_form.timezone.value
pagesize = self.settings_page.settings_form.pagesize.value
loglines = self.settings_page.settings_form.loglines.value
loglines = self.settings_page.settings_form.instance_log_length.value
user_settings = (("Language", changed_settings["language"], language),
("Timezone", changed_settings["timezone"], timezone),