From fb263eb3cfbde2a2574575a84db2de010c2361db Mon Sep 17 00:00:00 2001 From: Felipe Monteiro Date: Mon, 12 Dec 2016 11:42:33 -0500 Subject: [PATCH] Add UI Tests for Filtering Apps by Tag/Description. Also made the following changes: - Renamed test_check_search_option -> test_filter_by_name, because now that there are multiple search option tests, this test more precisely conveys what it is testing. - Added helper function wait_for_page_reload to base.py, because after a filter is conducted, a page refresh is performed; on slow machines, not waiting for page refresh throws error, because content hasn't loaded yet. Change-Id: Ifecba6563877de7d28b3d3ab4e2b77774b993c7e Partial-Bug: #1596196 --- muranodashboard/tests/functional/base.py | 7 ++ .../tests/functional/sanity_check.py | 91 ++++++++++++++++++- muranodashboard/tests/functional/utils.py | 12 ++- 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/muranodashboard/tests/functional/base.py b/muranodashboard/tests/functional/base.py index bd679fe3d..b65a6618d 100644 --- a/muranodashboard/tests/functional/base.py +++ b/muranodashboard/tests/functional/base.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import contextlib import json import logging import os @@ -384,6 +385,12 @@ class UITestCase(BaseDeps): (by.By.CSS_SELECTOR, "nav#sidebar a.active"))) time.sleep(0.5) + @contextlib.contextmanager + def wait_for_page_reload(self, sec=10): + old_page = self.driver.find_element_by_tag_name('html') + yield + ui.WebDriverWait(self, sec).until(EC.staleness_of(old_page)) + class PackageBase(UITestCase): @classmethod diff --git a/muranodashboard/tests/functional/sanity_check.py b/muranodashboard/tests/functional/sanity_check.py index 8c1792fd8..c1d5ab898 100644 --- a/muranodashboard/tests/functional/sanity_check.py +++ b/muranodashboard/tests/functional/sanity_check.py @@ -678,24 +678,107 @@ class TestSuiteApplications(base.ApplicationTestCase): self.delete_component() self.check_element_not_on_page(by.By.LINK_TEXT, 'TestA') - def test_check_search_option(self): + def test_filter_by_name(self): """Test checks that 'Search' option is operable. Scenario: 1. Navigate to 'Catalog > Browse' panel - 2. Set search criterion in the search field(e.g 'PostgreSQL') + 2. Set search criterion in the search field (e.g 'PostgreSQL') 3. Click on 'Filter' and check result """ self.navigate_to('Browse') self.go_to_submenu('Browse Local') self.fill_field(by.By.CSS_SELECTOR, 'input.form-control', 'PostgreSQL') - self.driver.find_element_by_id('apps__action_filter').click() - + with self.wait_for_page_reload(): + self.driver.find_element_by_id('apps__action_filter').click() self.check_element_on_page(by.By.XPATH, c.App.format('PostgreSQL')) + self.check_element_not_on_page(by.By.XPATH, + c.App.format('DeployingApp')) + self.check_element_not_on_page(by.By.XPATH, + c.App.format('HotExample')) self.check_element_not_on_page(by.By.XPATH, c.App.format('MockApp')) + def test_filter_by_tag(self): + """Test filtering by tag. + + Test checks ability to filter applications by tag in Catalog page. + + Scenario: + 1. Navigate to 'Catalog' > 'Browse' panel + 2. For each tag in ``apps_by_tag.keys()``: + a. Set search criterion in search field to current tag. + b. Click on 'Filter' and verify that expected applications are + shown and unexpected applications are not shown. + """ + self.navigate_to('Browse') + self.go_to_submenu('Browse Local') + + apps_by_tag = { + 'tag': ['DeployingApp', 'MockApp', 'PostgreSQL'], + 'hot': ['HotExample'] + } + all_apps = ['DeployingApp', 'HotExample', 'MockApp', 'PostgreSQL'] + + for tag, name_list in apps_by_tag.items(): + self.fill_field(by.By.CSS_SELECTOR, 'input.form-control', tag) + with self.wait_for_page_reload(): + self.driver.find_element_by_id('apps__action_filter').click() + for name in name_list: + self.check_element_on_page(by.By.XPATH, + c.App.format(name)) + for name in set(all_apps) - set(name_list): + self.check_element_not_on_page(by.By.XPATH, + c.App.format(name)) + + def test_filter_by_description(self): + """Test filtering by description. + + Test checks ability to filter applications by description in Catalog + page. Before beginning scenario, the test creates an app & package w/ a + randomly generated description (because otherwise all descriptions + would be identical). + + Scenario: + 1. Navigate to 'Catalog' > 'Browse' panel + 2. For each description in ``apps_by_description.keys()``: + a. Set search criterion in search field to current description. + b. Click on 'Filter' and verify that expected applications are + shown and unexpected applications are not shown. + """ + app_name = self.gen_random_resource_name('app_name', 8) + description = self.gen_random_resource_name('description', 8) + metadata = {"categories": ["Web"], "tags": ["tag"]} + manifest_kwargs = {'Description': description} + pkg_id = utils.upload_app_package(self.murano_client, app_name, + metadata, **manifest_kwargs) + + self.navigate_to('Browse') + self.go_to_submenu('Browse Local') + + apps_by_description = { + 'MockApp for webUI tests': ['DeployingApp', 'MockApp', + 'PostgreSQL', 'HotExample'], + description: [app_name] + } + all_apps = ['DeployingApp', 'HotExample', 'MockApp', 'PostgreSQL', + app_name] + + for description, name_list in apps_by_description.items(): + self.fill_field(by.By.CSS_SELECTOR, 'input.form-control', + description) + with self.wait_for_page_reload(): + self.driver.find_element_by_id('apps__action_filter').click() + for name in name_list: + self.check_element_on_page(by.By.XPATH, + c.App.format(name)) + for name in set(all_apps) - set(name_list): + self.check_element_not_on_page(by.By.XPATH, + c.App.format(name)) + + self.murano_client.packages.delete(pkg_id) + def test_filter_by_category(self): """Test filtering by category diff --git a/muranodashboard/tests/functional/utils.py b/muranodashboard/tests/functional/utils.py index 63d67a1ae..c61c51e9d 100644 --- a/muranodashboard/tests/functional/utils.py +++ b/muranodashboard/tests/functional/utils.py @@ -46,15 +46,17 @@ class ImageException(Exception): def upload_app_package(client, app_name, data, hot=False, - package_dir=consts.PackageDir): + package_dir=consts.PackageDir, **manifest_kwargs): try: if not hot: manifest = os.path.join(package_dir, 'manifest.yaml') - archive = compose_package(app_name, manifest, package_dir) + archive = compose_package(app_name, manifest, package_dir, + **manifest_kwargs) else: manifest = os.path.join(consts.HotPackageDir, 'manifest.yaml') archive = compose_package(app_name, manifest, - consts.HotPackageDir, hot=True) + consts.HotPackageDir, hot=True, + **manifest_kwargs) package = client.packages.create(data, {app_name: open(archive, 'rb')}) return package.id finally: @@ -63,7 +65,7 @@ def upload_app_package(client, app_name, data, hot=False, def compose_package(app_name, manifest, package_dir, - require=None, archive_dir=None, hot=False): + require=None, archive_dir=None, hot=False, **kwargs): """Composes a murano package Composes package `app_name` with `manifest` file as a template for the @@ -84,6 +86,8 @@ def compose_package(app_name, manifest, package_dir, mfest_copy['Classes'] = {fqn: 'mock_muranopl.yaml'} if require: mfest_copy['Require'] = require + if kwargs: + mfest_copy.update(kwargs) f.write(yaml.dump(mfest_copy, default_flow_style=False)) name = app_name + '.zip'