From 8774c23a4f8acee6c263ac00407af8784aeedd52 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Wed, 7 Jun 2017 10:25:07 +0100 Subject: [PATCH 01/28] Add some routines for the tests and simplify tests --- selenium_tests/selenium_test_base.py | 93 +++++++++++--------- selenium_tests/test_admin_name_header_bug.py | 12 +-- selenium_tests/test_hide_application.py | 11 +-- selenium_tests/test_login_logout.py | 18 ++-- selenium_tests/test_start_stop_container.py | 22 ++--- 5 files changed, 74 insertions(+), 82 deletions(-) diff --git a/selenium_tests/selenium_test_base.py b/selenium_tests/selenium_test_base.py index 4a3b11a55..47a29cdde 100644 --- a/selenium_tests/selenium_test_base.py +++ b/selenium_tests/selenium_test_base.py @@ -3,6 +3,9 @@ import os import contextlib import sqlite3 +import selenium.webdriver.support.expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.by import By from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoAlertPresentException @@ -23,6 +26,7 @@ def setUp(self): capabilities=capabilities, timeout=60) self.driver.implicitly_wait(30) + self.wait = WebDriverWait(self.driver, 30) self.base_url = "https://127.0.0.1:8000/" self.verificationErrors = [] self.accept_next_alert = True @@ -38,19 +42,32 @@ def setUp(self): base_url=self.base_url)) db.commit() - def is_element_present(self, how, what): - try: - self.driver.find_element(by=how, value=what) - except NoSuchElementException as e: - return False - return True + def wait_until_element_present(self, how, what): + return self.wait.until(EC.presence_of_element_located((how, what))) - def is_alert_present(self): - try: - self.driver.switch_to_alert() - except NoAlertPresentException as e: - return False - return True + def wait_until_alert_present(self): + return self.wait.until(EC.alert_is_present) + + def wait_until_text_inside(self, how, what, text): + return self.wait.until(EC.text_to_be_present_in_element((how, what), text)) + + def wait_until_element_visible(self, how, what): + return self.wait.until(EC.visibility_of_element_located((how, what))) + + def wait_until_element_invisible(self, how, what): + return self.wait.until(EC.invisibility_of_element_located((how, what))) + + def wait_until_element_clickable(self, how, what): + return self.wait.until(EC.element_to_be_clickable((how, what))) + + def click_element_located(self, how, what): + element = self.wait_until_element_clickable(how, what) + element.click() + + def type_text_in_element_located(self, how, what, text): + element = self.wait_until_element_clickable(how, what) + element.clear() + element.send_keys(text) def close_alert_and_get_its_text(self): try: @@ -75,12 +92,6 @@ def wait_for(self, check_func, timeout=30): else: self.fail("time out") - def click_by_css_selector(self, css_selector): - # Workaround for some unexpected behavior with clicking some elements. - self.driver.execute_script( - "arguments[0].click()", - self.driver.find_element_by_css_selector(css_selector)) - def click_button(self, button_text, number=0): """ Clicks a button with a given text. @@ -108,42 +119,40 @@ def tearDown(self): self.driver.quit() self.assertEqual([], self.verificationErrors) - @contextlib.contextmanager def login(self, username="test"): - driver = self.driver - driver.get(self.base_url + "/hub/login") + self.driver.get(self.base_url + "/hub/login") + + self.type_text_in_element_located(By.ID, "username_input", username) + self.type_text_in_element_located(By.ID, "password_input", username) - driver.find_element_by_id("username_input").clear() - driver.find_element_by_id("username_input").send_keys(username) - driver.find_element_by_id("password_input").clear() - driver.find_element_by_id("password_input").send_keys(username) - driver.find_element_by_id("login_submit").click() + self.click_element_located(By.ID, "login_submit") + + def logout(self): + self.click_element_located(By.CLASS_NAME, "user-menu") + self.click_element_located(By.ID, "logout") + self.wait_until_text_inside(By.CSS_SELECTOR, "div.auth-form-header", "Sign in") + + @contextlib.contextmanager + def logged_in(self, username="test"): + self.login(username) try: yield finally: - driver.find_element_by_css_selector(".user-menu").click() - driver.find_element_by_id("logout").click() - self.wait_for( - lambda: "Sign in" == driver.find_element_by_css_selector( - "div.auth-form-header").text - ) + self.logout() @contextlib.contextmanager def running_container(self): - with self.login(): + with self.logged_in(): driver = self.driver - self.wait_for(lambda: - driver.find_element_by_css_selector( - "#loading-spinner").value_of_css_property( - 'display') == "none") + self.wait_until_element_invisible(By.ID, "loading-spinner") - self.click_by_css_selector("#applistentries > li > a > img") - self.click_by_css_selector(".start-button") + self.click_element_located(By.CSS_SELECTOR, "#applistentries > li > a > img") + self.click_element_located(By.CLASS_NAME, "start-button") try: yield finally: - driver.find_element_by_id("application") - self.click_by_css_selector(".dropdown > a > img") - self.click_by_css_selector("#stop-button") + self.wait_until_element_present(By.ID, "application") + self.click_element_located(By.CSS_SELECTOR, ".dropdown > a > img") + self.click_element_located(By.ID, "stop-button") diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index 08825d5fb..12a792eba 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -1,13 +1,13 @@ from selenium_tests.selenium_test_base import SeleniumTestBase +from selenium.webdriver.common.by import By class TestAdminNameHeaderBug(SeleniumTestBase): def test_admin_name_header_bug(self): driver = self.driver - with self.login("admin"): - driver.find_element_by_link_text("Users").click() + with self.logged_in("admin"): + self.click_element_located(By.LINK_TEXT, "Users") + self.click_button("Policies") - self.wait_for(lambda: - "admin" == driver.find_element_by_css_selector( - "span.hidden-xs").text - ) + + self.wait_until_text_inside(By.CSS_SELECTOR, "span.hidden-xs", "admin") diff --git a/selenium_tests/test_hide_application.py b/selenium_tests/test_hide_application.py index 0a77f2def..d77d5b1f7 100644 --- a/selenium_tests/test_hide_application.py +++ b/selenium_tests/test_hide_application.py @@ -6,17 +6,12 @@ class TestHideApplication(SeleniumTestBase): def test_hide_application(self): driver = self.driver - with self.login(): - self.wait_for(lambda: - driver.find_element_by_css_selector( - "#loading-spinner").value_of_css_property( - 'display') == "none") + with self.logged_in(): + self.wait_until_element_invisible(By.ID, "loading-spinner") # Click on the search box search_box = driver.find_element_by_name("q") search_box.clear() search_box.send_keys('foobarheho') - self.wait_for(lambda: - not self.is_element_present( - By.CSS_SELECTOR, '#applistentries > li')) + self.wait_until_text_inside(By.ID, "applistentries", "") diff --git a/selenium_tests/test_login_logout.py b/selenium_tests/test_login_logout.py index 3c77a5b24..320ab0a23 100644 --- a/selenium_tests/test_login_logout.py +++ b/selenium_tests/test_login_logout.py @@ -1,20 +1,12 @@ # -*- coding: utf-8 -*- from selenium_tests.selenium_test_base import SeleniumTestBase +from selenium.webdriver.common.by import By class TestLoginLogout(SeleniumTestBase): def test_login_logout(self): - driver = self.driver - driver.get(self.base_url + "/hub/login") + self.login("test") - driver.find_element_by_id("username_input").clear() - driver.find_element_by_id("username_input").send_keys("test") - driver.find_element_by_id("password_input").clear() - driver.find_element_by_id("password_input").send_keys("test") - driver.find_element_by_id("login_submit").click() - driver.find_element_by_id("applistentries") - driver.find_element_by_css_selector(".user-menu").click() - driver.find_element_by_id("logout").click() - self.wait_for( - lambda: "Sign in" == driver.find_element_by_css_selector("div.auth-form-header").text - ) + self.wait_until_element_visible(By.ID, "applistentries") + + self.logout() diff --git a/selenium_tests/test_start_stop_container.py b/selenium_tests/test_start_stop_container.py index 7cbc4ad0e..b7ce02a9f 100644 --- a/selenium_tests/test_start_stop_container.py +++ b/selenium_tests/test_start_stop_container.py @@ -1,25 +1,21 @@ # -*- coding: utf-8 -*- from selenium.webdriver.common.action_chains import ActionChains from selenium_tests.selenium_test_base import SeleniumTestBase +from selenium.webdriver.common.by import By class TestContainerInteraction(SeleniumTestBase): def test_start_stop_container(self): driver = self.driver - with self.login(): - self.wait_for(lambda: - driver.find_element_by_css_selector( - "#loading-spinner").value_of_css_property( - 'display') == "none") + with self.logged_in(): + self.wait_until_element_invisible(By.ID, "loading-spinner") - self.click_by_css_selector("#applistentries > li > a > img") - self.click_by_css_selector(".start-button") + self.click_element_located(By.CSS_SELECTOR, "#applistentries > li > a > img") + self.click_element_located(By.CLASS_NAME, "start-button") - driver.find_element_by_id("application") - - self.click_by_css_selector(".dropdown > a > img") - - self.click_by_css_selector("#stop-button") + self.wait_until_element_present(By.ID, "application") + self.click_element_located(By.CSS_SELECTOR, ".dropdown > a > img") + self.click_element_located(By.ID, "stop-button") def test_focus(self): driver = self.driver @@ -33,6 +29,6 @@ def test_focus(self): self.assertNotEqual(iframe, self.driver.switch_to.active_element) - self.click_by_css_selector("#applistentries > li > a > img") + self.click_element_located(By.CSS_SELECTOR, "#applistentries > li > a > img") self.assertEqual(iframe, self.driver.switch_to.active_element) From 07404c166a1779bf059e0b7e8715e754223209d4 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Wed, 7 Jun 2017 11:10:18 +0100 Subject: [PATCH 02/28] Add some ids to simplify code and create select_application routine --- .../user/vue-components/ApplicationLabel.vue | 2 +- .../vue-components/ApplicationListView.vue | 3 ++- .../user/vue-components/ApplicationView.vue | 2 +- remoteappmanager/templates/page.html | 2 +- selenium_tests/selenium_test_base.py | 16 ++++++++++------ selenium_tests/test_admin_name_header_bug.py | 1 - selenium_tests/test_hide_application.py | 6 +----- selenium_tests/test_start_stop_container.py | 18 +++++++----------- 8 files changed, 23 insertions(+), 27 deletions(-) diff --git a/frontend/user/vue-components/ApplicationLabel.vue b/frontend/user/vue-components/ApplicationLabel.vue index 2a9dea9a3..609b51fbe 100644 --- a/frontend/user/vue-components/ApplicationLabel.vue +++ b/frontend/user/vue-components/ApplicationLabel.vue @@ -1,6 +1,6 @@ diff --git a/frontend/vue/toolkit/DataTable.vue b/frontend/vue/toolkit/DataTable.vue index c8941d2fe..fcef5fa76 100644 --- a/frontend/vue/toolkit/DataTable.vue +++ b/frontend/vue/toolkit/DataTable.vue @@ -1,7 +1,9 @@ - diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index d676e9f64..c403ab18a 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -12,10 +12,20 @@ def click_submit_button(self): self.click_element_located(By.ID, "modal-submit-btn") self.wait_until_modal_closed() + def click_ok_button(self): + self.click_element_located(By.ID, "modal-ok-btn") + self.wait_until_modal_closed() + def click_cancel_button(self): self.click_element_located(By.ID, "modal-cancel-btn") self.wait_until_modal_closed() + def click_policy_user(self, index=0): + self.click_element_located(By.ID, "row-{}-action-0".format(index)) + + def click_remove_user(self, index=0): + self.click_element_located(By.ID, "row-{}-action-1".format(index)) + @contextlib.contextmanager def logged_in(self): self.login("admin") diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index 3b422b071..d52a95b0c 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -7,6 +7,6 @@ def test_admin_name_header_bug(self): with self.logged_in(): self.click_element_located(By.LINK_TEXT, "Users") - # self.click_button("Policies") + self.click_policy_user() self.wait_until_text_inside(By.CSS_SELECTOR, "span.hidden-xs", "admin") diff --git a/selenium_tests/test_create_new_user.py b/selenium_tests/test_create_new_user.py index c5059ccff..237a15a0d 100644 --- a/selenium_tests/test_create_new_user.py +++ b/selenium_tests/test_create_new_user.py @@ -8,15 +8,17 @@ def test_cancel(self): self.click_element_located(By.LINK_TEXT, "Users") self.click_new_entry_button() - self.click_cancel_button() - def test_create_user(self): + def test_create_and_remove_user(self): with self.logged_in(): self.click_element_located(By.LINK_TEXT, "Users") self.click_new_entry_button() - self.type_text_in_element_located(By.ID, "new-user-name", "mrenou") - self.click_submit_button() + + # Click remove button + self.click_remove_user(1) + + self.click_ok_button() From 5822529928dbd33160d8fbe93c6432585b8fe973 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Wed, 7 Jun 2017 16:03:15 +0100 Subject: [PATCH 10/28] Reduce routines verbosity --- selenium_tests/UserDriverTest.py | 16 ++++++++-------- selenium_tests/test_start_stop_container.py | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/selenium_tests/UserDriverTest.py b/selenium_tests/UserDriverTest.py index 0336ebf2b..779f4661d 100644 --- a/selenium_tests/UserDriverTest.py +++ b/selenium_tests/UserDriverTest.py @@ -11,16 +11,16 @@ def select_application(self, index=0): def open_application_settings(self): self.click_element_located(By.ID, "application-settings") - def stop_selected_application(self): + def stop_application(self): self.click_element_located(By.ID, "stop-button") - def start_selected_application(self): + def start_application(self): self.click_element_located(By.ID, "start-button") - def wait_until_selected_application_running(self): + def wait_until_application_running(self): self.wait_until_element_present(By.ID, "application") - def wait_until_selected_application_stopped(self): + def wait_until_application_stopped(self): self.wait_until_text_inside(By.ID, "start-button", "Start") def wait_until_application_list_loaded(self): @@ -40,13 +40,13 @@ def running_container(self, index=0): self.wait_until_application_list_loaded() self.select_application(index) - self.start_selected_application() + self.start_application() try: yield finally: self.select_application(index) - self.wait_until_selected_application_running() + self.wait_until_application_running() self.open_application_settings() - self.stop_selected_application() - self.wait_until_selected_application_stopped() + self.stop_application() + self.wait_until_application_stopped() diff --git a/selenium_tests/test_start_stop_container.py b/selenium_tests/test_start_stop_container.py index d5b23cdeb..ca3a1319e 100644 --- a/selenium_tests/test_start_stop_container.py +++ b/selenium_tests/test_start_stop_container.py @@ -9,12 +9,12 @@ def test_start_stop_container(self): self.wait_until_application_list_loaded() self.select_application() - self.start_selected_application() - self.wait_until_selected_application_running() + self.start_application() + self.wait_until_application_running() self.open_application_settings() - self.stop_selected_application() - self.wait_until_selected_application_stopped() + self.stop_application() + self.wait_until_application_stopped() def test_focus(self): with self.running_container(): From 9d8f849e794d0f8c7a6ab91aaf374e18e0e9e9ae Mon Sep 17 00:00:00 2001 From: martinRenou Date: Wed, 7 Jun 2017 16:07:10 +0100 Subject: [PATCH 11/28] Rename routine --- selenium_tests/AdminDriverTest.py | 2 +- selenium_tests/test_admin_name_header_bug.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index c403ab18a..07af78b0d 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -20,7 +20,7 @@ def click_cancel_button(self): self.click_element_located(By.ID, "modal-cancel-btn") self.wait_until_modal_closed() - def click_policy_user(self, index=0): + def click_user_policy(self, index=0): self.click_element_located(By.ID, "row-{}-action-0".format(index)) def click_remove_user(self, index=0): diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index d52a95b0c..be6db5fa3 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -7,6 +7,6 @@ def test_admin_name_header_bug(self): with self.logged_in(): self.click_element_located(By.LINK_TEXT, "Users") - self.click_policy_user() + self.click_user_policy(0) self.wait_until_text_inside(By.CSS_SELECTOR, "span.hidden-xs", "admin") From 85e70b3254cea8901dbe091eaaebc6b4745d4036 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Wed, 7 Jun 2017 19:19:01 +0100 Subject: [PATCH 12/28] Rename routine --- selenium_tests/AdminDriverTest.py | 2 +- selenium_tests/test_admin_name_header_bug.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index 07af78b0d..0758339fb 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -20,7 +20,7 @@ def click_cancel_button(self): self.click_element_located(By.ID, "modal-cancel-btn") self.wait_until_modal_closed() - def click_user_policy(self, index=0): + def click_user_policies(self, index=0): self.click_element_located(By.ID, "row-{}-action-0".format(index)) def click_remove_user(self, index=0): diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index be6db5fa3..17f0c5992 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -7,6 +7,6 @@ def test_admin_name_header_bug(self): with self.logged_in(): self.click_element_located(By.LINK_TEXT, "Users") - self.click_user_policy(0) + self.click_user_policies(0) self.wait_until_text_inside(By.CSS_SELECTOR, "span.hidden-xs", "admin") From 5989f8940c1195cf5e27bcb2f4db933d60e0cbb8 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Thu, 8 Jun 2017 11:19:58 +0100 Subject: [PATCH 13/28] Remove ids for modal dialogs --- .../admin/vue-components/accounting/NewAccountingDialog.vue | 4 ++-- .../vue-components/applications/NewApplicationDialog.vue | 4 ++-- frontend/admin/vue-components/users/NewUserDialog.vue | 6 +++--- selenium_tests/AdminDriverTest.py | 6 +++--- selenium_tests/test_create_new_user.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/admin/vue-components/accounting/NewAccountingDialog.vue b/frontend/admin/vue-components/accounting/NewAccountingDialog.vue index 2a23ec5c1..3b9845e3c 100644 --- a/frontend/admin/vue-components/accounting/NewAccountingDialog.vue +++ b/frontend/admin/vue-components/accounting/NewAccountingDialog.vue @@ -48,8 +48,8 @@
Error: {{communicationError}}
- - + + diff --git a/frontend/admin/vue-components/applications/NewApplicationDialog.vue b/frontend/admin/vue-components/applications/NewApplicationDialog.vue index 0ba027b94..1e696f1e2 100644 --- a/frontend/admin/vue-components/applications/NewApplicationDialog.vue +++ b/frontend/admin/vue-components/applications/NewApplicationDialog.vue @@ -14,8 +14,8 @@
Error: {{communicationError}}
- - + + diff --git a/frontend/admin/vue-components/users/NewUserDialog.vue b/frontend/admin/vue-components/users/NewUserDialog.vue index 8639339f3..0365039eb 100644 --- a/frontend/admin/vue-components/users/NewUserDialog.vue +++ b/frontend/admin/vue-components/users/NewUserDialog.vue @@ -5,14 +5,14 @@ - + User Name cannot be empty diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index 0758339fb..e70edc6e2 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -9,15 +9,15 @@ def click_new_entry_button(self): self.click_element_located(By.ID, "global-action-0") def click_submit_button(self): - self.click_element_located(By.ID, "modal-submit-btn") + self.click_element_located(By.XPATH, "//button[contains(text(),'Submit')]") self.wait_until_modal_closed() def click_ok_button(self): - self.click_element_located(By.ID, "modal-ok-btn") + self.click_element_located(By.XPATH, "//button[contains(text(),'Ok')]") self.wait_until_modal_closed() def click_cancel_button(self): - self.click_element_located(By.ID, "modal-cancel-btn") + self.click_element_located(By.XPATH, "//button[contains(text(),'Cancel')]") self.wait_until_modal_closed() def click_user_policies(self, index=0): diff --git a/selenium_tests/test_create_new_user.py b/selenium_tests/test_create_new_user.py index 237a15a0d..0bf39eafe 100644 --- a/selenium_tests/test_create_new_user.py +++ b/selenium_tests/test_create_new_user.py @@ -15,7 +15,7 @@ def test_create_and_remove_user(self): self.click_element_located(By.LINK_TEXT, "Users") self.click_new_entry_button() - self.type_text_in_element_located(By.ID, "new-user-name", "mrenou") + self.type_text_in_element_located(By.CSS_SELECTOR, ".modal-body > form > div > input", "mrenou") self.click_submit_button() # Click remove button From f0a11f677c2f9ca3dc4e61d9b59d2dbef8709c9d Mon Sep 17 00:00:00 2001 From: martinRenou Date: Thu, 8 Jun 2017 11:25:08 +0100 Subject: [PATCH 14/28] Rename click routine --- selenium_tests/AdminDriverTest.py | 12 ++++++------ selenium_tests/RemoteAppDriverTest.py | 8 ++++---- selenium_tests/UserDriverTest.py | 8 ++++---- selenium_tests/test_admin_name_header_bug.py | 2 +- selenium_tests/test_create_new_user.py | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index e70edc6e2..5f0b35542 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -6,25 +6,25 @@ class AdminDriverTest(RemoteAppDriverTest): def click_new_entry_button(self): - self.click_element_located(By.ID, "global-action-0") + self.click_first_element_located(By.ID, "global-action-0") def click_submit_button(self): - self.click_element_located(By.XPATH, "//button[contains(text(),'Submit')]") + self.click_first_element_located(By.XPATH, "//button[contains(text(),'Submit')]") self.wait_until_modal_closed() def click_ok_button(self): - self.click_element_located(By.XPATH, "//button[contains(text(),'Ok')]") + self.click_first_element_located(By.XPATH, "//button[contains(text(),'Ok')]") self.wait_until_modal_closed() def click_cancel_button(self): - self.click_element_located(By.XPATH, "//button[contains(text(),'Cancel')]") + self.click_first_element_located(By.XPATH, "//button[contains(text(),'Cancel')]") self.wait_until_modal_closed() def click_user_policies(self, index=0): - self.click_element_located(By.ID, "row-{}-action-0".format(index)) + self.click_first_element_located(By.ID, "row-{}-action-0".format(index)) def click_remove_user(self, index=0): - self.click_element_located(By.ID, "row-{}-action-1".format(index)) + self.click_first_element_located(By.ID, "row-{}-action-1".format(index)) @contextlib.contextmanager def logged_in(self): diff --git a/selenium_tests/RemoteAppDriverTest.py b/selenium_tests/RemoteAppDriverTest.py index 025609690..79cd24e8e 100644 --- a/selenium_tests/RemoteAppDriverTest.py +++ b/selenium_tests/RemoteAppDriverTest.py @@ -57,7 +57,7 @@ def wait_until_element_invisible(self, how, what): def wait_until_element_clickable(self, how, what): return self.wait.until(EC.element_to_be_clickable((how, what))) - def click_element_located(self, how, what): + def click_first_element_located(self, how, what): element = self.wait_until_element_clickable(how, what) element.click() @@ -75,11 +75,11 @@ def login(self, username="test"): self.type_text_in_element_located(By.ID, "username_input", username) self.type_text_in_element_located(By.ID, "password_input", username) - self.click_element_located(By.ID, "login_submit") + self.click_first_element_located(By.ID, "login_submit") def logout(self): - self.click_element_located(By.ID, "user-menu") - self.click_element_located(By.ID, "logout") + self.click_first_element_located(By.ID, "user-menu") + self.click_first_element_located(By.ID, "logout") self.wait_until_text_inside(By.CSS_SELECTOR, "div.auth-form-header", "Sign in") def tearDown(self): diff --git a/selenium_tests/UserDriverTest.py b/selenium_tests/UserDriverTest.py index 779f4661d..e81678dcb 100644 --- a/selenium_tests/UserDriverTest.py +++ b/selenium_tests/UserDriverTest.py @@ -6,16 +6,16 @@ class UserDriverTest(RemoteAppDriverTest): def select_application(self, index=0): - self.click_element_located(By.ID, "application-entry-{}".format(index)) + self.click_first_element_located(By.ID, "application-entry-{}".format(index)) def open_application_settings(self): - self.click_element_located(By.ID, "application-settings") + self.click_first_element_located(By.ID, "application-settings") def stop_application(self): - self.click_element_located(By.ID, "stop-button") + self.click_first_element_located(By.ID, "stop-button") def start_application(self): - self.click_element_located(By.ID, "start-button") + self.click_first_element_located(By.ID, "start-button") def wait_until_application_running(self): self.wait_until_element_present(By.ID, "application") diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index 17f0c5992..01c87fd0e 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -5,7 +5,7 @@ class TestAdminNameHeaderBug(AdminDriverTest): def test_admin_name_header_bug(self): with self.logged_in(): - self.click_element_located(By.LINK_TEXT, "Users") + self.click_first_element_located(By.LINK_TEXT, "Users") self.click_user_policies(0) diff --git a/selenium_tests/test_create_new_user.py b/selenium_tests/test_create_new_user.py index 0bf39eafe..d800b5c55 100644 --- a/selenium_tests/test_create_new_user.py +++ b/selenium_tests/test_create_new_user.py @@ -5,14 +5,14 @@ class TestCreateNewUser(AdminDriverTest): def test_cancel(self): with self.logged_in(): - self.click_element_located(By.LINK_TEXT, "Users") + self.click_first_element_located(By.LINK_TEXT, "Users") self.click_new_entry_button() self.click_cancel_button() def test_create_and_remove_user(self): with self.logged_in(): - self.click_element_located(By.LINK_TEXT, "Users") + self.click_first_element_located(By.LINK_TEXT, "Users") self.click_new_entry_button() self.type_text_in_element_located(By.CSS_SELECTOR, ".modal-body > form > div > input", "mrenou") From 36bc29176d1c5175586f6efaf42ec26f96274c91 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Thu, 8 Jun 2017 11:34:22 +0100 Subject: [PATCH 15/28] Add a routine for clicking a button by innertext --- selenium_tests/AdminDriverTest.py | 6 +++--- selenium_tests/RemoteAppDriverTest.py | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index 5f0b35542..1051c89dd 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -9,15 +9,15 @@ def click_new_entry_button(self): self.click_first_element_located(By.ID, "global-action-0") def click_submit_button(self): - self.click_first_element_located(By.XPATH, "//button[contains(text(),'Submit')]") + self.click_first_button("Submit") self.wait_until_modal_closed() def click_ok_button(self): - self.click_first_element_located(By.XPATH, "//button[contains(text(),'Ok')]") + self.click_first_button("Ok") self.wait_until_modal_closed() def click_cancel_button(self): - self.click_first_element_located(By.XPATH, "//button[contains(text(),'Cancel')]") + self.click_first_button("Cancel") self.wait_until_modal_closed() def click_user_policies(self, index=0): diff --git a/selenium_tests/RemoteAppDriverTest.py b/selenium_tests/RemoteAppDriverTest.py index 79cd24e8e..63faed011 100644 --- a/selenium_tests/RemoteAppDriverTest.py +++ b/selenium_tests/RemoteAppDriverTest.py @@ -61,6 +61,11 @@ def click_first_element_located(self, how, what): element = self.wait_until_element_clickable(how, what) element.click() + def click_first_button(self, name): + self.click_first_element_located( + By.XPATH, "//button[contains(text(),'{}')]".format(name) + ) + def type_text_in_element_located(self, how, what, text): element = self.wait_until_element_clickable(how, what) element.clear() From 47a26f186594d4bb78fc90667d2f1c23a03740b8 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Thu, 8 Jun 2017 13:28:02 +0100 Subject: [PATCH 16/28] Clear routine names It is now clearer the difference between located element and raw elements --- selenium_tests/RemoteAppDriverTest.py | 26 ++++++++++++++------ selenium_tests/UserDriverTest.py | 6 ++--- selenium_tests/test_admin_name_header_bug.py | 2 +- selenium_tests/test_hide_application.py | 2 +- selenium_tests/test_login_logout.py | 2 +- selenium_tests/test_start_stop_container.py | 2 +- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/selenium_tests/RemoteAppDriverTest.py b/selenium_tests/RemoteAppDriverTest.py index 63faed011..37b7ecaf3 100644 --- a/selenium_tests/RemoteAppDriverTest.py +++ b/selenium_tests/RemoteAppDriverTest.py @@ -42,23 +42,33 @@ def setUp(self): base_url=self.base_url)) db.commit() - def wait_until_element_present(self, how, what): + def wait_until_presence_of_element_located(self, how, what): return self.wait.until(EC.presence_of_element_located((how, what))) - def wait_until_text_inside(self, how, what, text): + def wait_until_text_inside_element_located(self, how, what, text): return self.wait.until(EC.text_to_be_present_in_element((how, what), text)) - def wait_until_element_visible(self, how, what): + def wait_until_visibility_of_element_located(self, how, what): return self.wait.until(EC.visibility_of_element_located((how, what))) - def wait_until_element_invisible(self, how, what): + def wait_until_visibility_of(self, element): + return self.wait.until(EC.visibility_of(element)) + + def wait_until_invisibility_of_element_located(self, how, what): return self.wait.until(EC.invisibility_of_element_located((how, what))) - def wait_until_element_clickable(self, how, what): + def wait_until_clickability_of_element_located(self, how, what): return self.wait.until(EC.element_to_be_clickable((how, what))) + def wait_until_clickability_of(self, element): + pass + def click_first_element_located(self, how, what): - element = self.wait_until_element_clickable(how, what) + element = self.wait_until_clickability_of_element_located(how, what) + element.click() + + def click_element(self, element): + self.wait_until_clickability_of(element) element.click() def click_first_button(self, name): @@ -67,7 +77,7 @@ def click_first_button(self, name): ) def type_text_in_element_located(self, how, what, text): - element = self.wait_until_element_clickable(how, what) + element = self.wait_until_clickability_of_element_located(how, what) element.clear() element.send_keys(text) @@ -85,7 +95,7 @@ def login(self, username="test"): def logout(self): self.click_first_element_located(By.ID, "user-menu") self.click_first_element_located(By.ID, "logout") - self.wait_until_text_inside(By.CSS_SELECTOR, "div.auth-form-header", "Sign in") + self.wait_until_text_inside_element_located(By.CSS_SELECTOR, "div.auth-form-header", "Sign in") def tearDown(self): self.driver.quit() diff --git a/selenium_tests/UserDriverTest.py b/selenium_tests/UserDriverTest.py index e81678dcb..b6df610a4 100644 --- a/selenium_tests/UserDriverTest.py +++ b/selenium_tests/UserDriverTest.py @@ -18,13 +18,13 @@ def start_application(self): self.click_first_element_located(By.ID, "start-button") def wait_until_application_running(self): - self.wait_until_element_present(By.ID, "application") + self.wait_until_presence_of_element_located(By.ID, "application") def wait_until_application_stopped(self): - self.wait_until_text_inside(By.ID, "start-button", "Start") + self.wait_until_text_inside_element_located(By.ID, "start-button", "Start") def wait_until_application_list_loaded(self): - self.wait_until_element_invisible(By.ID, "loading-spinner") + self.wait_until_invisibility_of_element_located(By.ID, "loading-spinner") @contextlib.contextmanager def logged_in(self, username="test"): diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index 01c87fd0e..db7bf3f5b 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -9,4 +9,4 @@ def test_admin_name_header_bug(self): self.click_user_policies(0) - self.wait_until_text_inside(By.CSS_SELECTOR, "span.hidden-xs", "admin") + self.wait_until_text_inside_element_located(By.CSS_SELECTOR, "span.hidden-xs", "admin") diff --git a/selenium_tests/test_hide_application.py b/selenium_tests/test_hide_application.py index 26795bc40..307dbce11 100644 --- a/selenium_tests/test_hide_application.py +++ b/selenium_tests/test_hide_application.py @@ -10,4 +10,4 @@ def test_hide_application(self): self.type_text_in_element_located(By.ID, "search-input", "foobarheho") - self.wait_until_text_inside(By.ID, "applistentries", "") + self.wait_until_text_inside_element_located(By.ID, "applistentries", "") diff --git a/selenium_tests/test_login_logout.py b/selenium_tests/test_login_logout.py index 1c3490d40..684e748c4 100644 --- a/selenium_tests/test_login_logout.py +++ b/selenium_tests/test_login_logout.py @@ -7,6 +7,6 @@ class TestLoginLogout(RemoteAppDriverTest): def test_login_logout(self): self.login("test") - self.wait_until_element_visible(By.ID, "applistentries") + self.wait_until_visibility_of_element_located(By.ID, "applistentries") self.logout() diff --git a/selenium_tests/test_start_stop_container.py b/selenium_tests/test_start_stop_container.py index ca3a1319e..01ba42762 100644 --- a/selenium_tests/test_start_stop_container.py +++ b/selenium_tests/test_start_stop_container.py @@ -18,7 +18,7 @@ def test_start_stop_container(self): def test_focus(self): with self.running_container(): - iframe = self.wait_until_element_visible(By.TAG_NAME, "iframe") + iframe = self.wait_until_visibility_of_element_located(By.TAG_NAME, "iframe") self.assertEqual(iframe, self.driver.switch_to.active_element) self.type_text_in_element_located(By.ID, "search-input", "") From a4baa9de3c21ad4528a740afa8ddb2234e280c2e Mon Sep 17 00:00:00 2001 From: martinRenou Date: Thu, 8 Jun 2017 14:51:09 +0100 Subject: [PATCH 17/28] Remove ids for datatable actions --- frontend/vue/toolkit/DataTable.vue | 6 ++---- selenium_tests/AdminDriverTest.py | 21 ++++++++++++++------ selenium_tests/RemoteAppDriverTest.py | 17 ++++++++++++++-- selenium_tests/test_admin_name_header_bug.py | 2 +- selenium_tests/test_create_new_user.py | 2 +- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/frontend/vue/toolkit/DataTable.vue b/frontend/vue/toolkit/DataTable.vue index 2497de401..0226036c9 100644 --- a/frontend/vue/toolkit/DataTable.vue +++ b/frontend/vue/toolkit/DataTable.vue @@ -1,8 +1,7 @@ - diff --git a/selenium_tests/AdminDriverTest.py b/selenium_tests/AdminDriverTest.py index 1051c89dd..429ca32d2 100644 --- a/selenium_tests/AdminDriverTest.py +++ b/selenium_tests/AdminDriverTest.py @@ -6,7 +6,7 @@ class AdminDriverTest(RemoteAppDriverTest): def click_new_entry_button(self): - self.click_first_element_located(By.ID, "global-action-0") + self.click_first_button("Create New Entry") def click_submit_button(self): self.click_first_button("Submit") @@ -20,11 +20,20 @@ def click_cancel_button(self): self.click_first_button("Cancel") self.wait_until_modal_closed() - def click_user_policies(self, index=0): - self.click_first_element_located(By.ID, "row-{}-action-0".format(index)) - - def click_remove_user(self, index=0): - self.click_first_element_located(By.ID, "row-{}-action-1".format(index)) + def _get_table_element(self, name): + # Select row which contains somewhere the given name + return self.driver.find_element_by_xpath( + "//tr[td[text()='{}']]".format(name) + ) + + def trigger_row_action(self, row, action_name): + # Select row + row = self._get_table_element(row) + # Get action button + action_btn = row.find_element_by_xpath( + "td/button[text()='{}']".format(action_name) + ) + self.click_element(action_btn) @contextlib.contextmanager def logged_in(self): diff --git a/selenium_tests/RemoteAppDriverTest.py b/selenium_tests/RemoteAppDriverTest.py index 37b7ecaf3..2fc848b27 100644 --- a/selenium_tests/RemoteAppDriverTest.py +++ b/selenium_tests/RemoteAppDriverTest.py @@ -13,6 +13,19 @@ import unittest +# Missing EC class +class clickability_of(object): + def __init__(self, element): + self.element = element + + def __call__(self, driver): + element = EC.visibility_of(self.element)(driver) + if element and element.is_enabled(): + return element + else: + return false + + class RemoteAppDriverTest(unittest.TestCase): def setUp(self): ff_binary = webdriver.firefox.firefox_binary.FirefoxBinary() @@ -61,7 +74,7 @@ def wait_until_clickability_of_element_located(self, how, what): return self.wait.until(EC.element_to_be_clickable((how, what))) def wait_until_clickability_of(self, element): - pass + return self.wait.until(clickability_of(element)) def click_first_element_located(self, how, what): element = self.wait_until_clickability_of_element_located(how, what) @@ -73,7 +86,7 @@ def click_element(self, element): def click_first_button(self, name): self.click_first_element_located( - By.XPATH, "//button[contains(text(),'{}')]".format(name) + By.XPATH, "//button[text()='{}']".format(name) ) def type_text_in_element_located(self, how, what, text): diff --git a/selenium_tests/test_admin_name_header_bug.py b/selenium_tests/test_admin_name_header_bug.py index db7bf3f5b..4ad949b73 100644 --- a/selenium_tests/test_admin_name_header_bug.py +++ b/selenium_tests/test_admin_name_header_bug.py @@ -7,6 +7,6 @@ def test_admin_name_header_bug(self): with self.logged_in(): self.click_first_element_located(By.LINK_TEXT, "Users") - self.click_user_policies(0) + self.trigger_row_action("test", "Policies") self.wait_until_text_inside_element_located(By.CSS_SELECTOR, "span.hidden-xs", "admin") diff --git a/selenium_tests/test_create_new_user.py b/selenium_tests/test_create_new_user.py index d800b5c55..738067434 100644 --- a/selenium_tests/test_create_new_user.py +++ b/selenium_tests/test_create_new_user.py @@ -19,6 +19,6 @@ def test_create_and_remove_user(self): self.click_submit_button() # Click remove button - self.click_remove_user(1) + self.trigger_row_action("mrenou", "Remove") self.click_ok_button() From 88e8af837d585990490ff2e2df5767466cd23dbd Mon Sep 17 00:00:00 2001 From: martinRenou Date: Thu, 8 Jun 2017 14:59:03 +0100 Subject: [PATCH 18/28] Undo change and remove trailing ids --- frontend/vue/toolkit/ConfirmDialog.vue | 4 ++-- frontend/vue/toolkit/DataTable.vue | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/vue/toolkit/ConfirmDialog.vue b/frontend/vue/toolkit/ConfirmDialog.vue index 7398f67ed..d35c2a73d 100644 --- a/frontend/vue/toolkit/ConfirmDialog.vue +++ b/frontend/vue/toolkit/ConfirmDialog.vue @@ -3,8 +3,8 @@ diff --git a/frontend/vue/toolkit/DataTable.vue b/frontend/vue/toolkit/DataTable.vue index 0226036c9..47bb12700 100644 --- a/frontend/vue/toolkit/DataTable.vue +++ b/frontend/vue/toolkit/DataTable.vue @@ -1,8 +1,7 @@