From 47fed5c819741c0dae52cac456a4a0f756ae1a44 Mon Sep 17 00:00:00 2001 From: Ramon Medeiros Date: Sat, 28 Dec 2019 15:55:04 +0100 Subject: [PATCH 1/6] Initial E2E tests for Kimchi --- .gitignore | 1 + uiTests/README.md | 39 +++++++++ uiTests/pages/kimchi_project/login.py | 61 +++++++++++++ uiTests/pages/kimchi_project/templates.py | 37 ++++++++ uiTests/pytest.ini | 2 + uiTests/requirements.txt | 28 ++++++ uiTests/test_templates.py | 31 +++++++ uiTests/utils.py | 101 ++++++++++++++++++++++ 8 files changed, 300 insertions(+) create mode 100644 uiTests/README.md create mode 100644 uiTests/pages/kimchi_project/login.py create mode 100644 uiTests/pages/kimchi_project/templates.py create mode 100644 uiTests/pytest.ini create mode 100644 uiTests/requirements.txt create mode 100644 uiTests/test_templates.py create mode 100644 uiTests/utils.py diff --git a/.gitignore b/.gitignore index 8069807af..9ccf48d54 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ po/gen-pot *.rej *.pem ui/pages/help/*/*.html +uiTests/.env diff --git a/uiTests/README.md b/uiTests/README.md new file mode 100644 index 000000000..81b665ecd --- /dev/null +++ b/uiTests/README.md @@ -0,0 +1,39 @@ +# Kimchi E2E Tests + +The tests are located in uiTests. You should go to the directory to start them +``` +$ cd uiTests +``` + +## How to run + +First you need to install all dependencies to run the tests + +### Optional: install a virtual environment + +``` +$ python3 -m venv .env +$ source .env/bin/activate +``` + +### Install deps +``` +$ pip install -r requirements.txt +``` + +### Run +The Makefile expect some environment variables to run kimchi, which are: + +``` +Expect environment variables: +KIMCHI_USERNAME: username for the host default: root +KIMCHI_PASSWORD: password for the host +KIMCHI_HOST: host for kimchi default: localhost +KIMCHI_PORT: port for kimchi default: 8001 +``` + +So, if you are running against a remote host: + +``` +$ read -s pass; KIMCHI_HOST= KIMCHI_PASSWORD=$pass make +``` \ No newline at end of file diff --git a/uiTests/pages/kimchi_project/login.py b/uiTests/pages/kimchi_project/login.py new file mode 100644 index 000000000..3e3a1ceac --- /dev/null +++ b/uiTests/pages/kimchi_project/login.py @@ -0,0 +1,61 @@ +import logging +import os +import utils + +# locators by ID +USERNAME = "username" +PASSWORD = "password" +LOGIN_BUTTON = "btn-login" +LOGIN_BAR = "user-login" + +# environment variables +ENV_USER = "KIMCHI_USERNAME" +ENV_PASS = "KIMCHI_PASSWORD" +ENV_PORT = "KIMCHI_PORT" +ENV_HOST = "KIMCHI_HOST" + + +class KimchiLoginPage(): + """ + Page object to Login + + Expect environment variables: + KIMCHI_USERNAME: username for the host + KIMCHI_PASSWORD: password for the host + KIMCHI_HOST: host for kimchi + KIMCHI_PORT: port for kimchi + """ + + def __init__(self, browser): + self.browser = browser + + # assert envs + assert ENV_USER in os.environ, f"{ENV_USER} is a required environment var" + assert ENV_PASS in os.environ, f"{ENV_PASS} is a required environment var" + assert ENV_HOST in os.environ, f"{ENV_HOST} is a required environment var" + + # get values + host = os.environ[ENV_HOST] + port = os.environ.get(ENV_PORT) or "8001" + self.user = os.environ[ENV_USER] + self.password = os.environ[ENV_PASS] + + self.browser.get(f"https://{host}:{port}/login.html") + + def login(self): + # fill user and password + utils.fillTextIfElementIsVisibleById(self.browser, + USERNAME, + self.user) + utils.fillTextIfElementIsVisibleById(self.browser, + PASSWORD, + self.password) + + # press login + utils.clickIfElementIsVisibleById(self.browser, LOGIN_BUTTON) + + # login bar not found: return error + if utils.waitElementIsVisibleById(self.browser, LOGIN_BAR) == False: + logging.error(f"Invalid credentials") + return False + return True diff --git a/uiTests/pages/kimchi_project/templates.py b/uiTests/pages/kimchi_project/templates.py new file mode 100644 index 000000000..57bbd4efe --- /dev/null +++ b/uiTests/pages/kimchi_project/templates.py @@ -0,0 +1,37 @@ +import utils +from .login import KimchiLoginPage + +VIRTUALIZATION_TAB = "//a[@class = 'item virtualizationTab']" +TEMPLATES_TAB = "//a[@href = 'plugins/kimchi/tabs/templates.html']" +ADD_TEMPLATE = "template-add" +ISOS_LIST = "list-local-iso" + +class KimchiTemplatePage(): + + def __init__(self, browser): + self.browser = browser + assert KimchiLoginPage(browser).login(), "Cannot login to Kimchi" + + def retrieveDefaulTemplates(self): + # click virtualization Tab + utils.clickIfElementIsVisibleByXpath(self.browser, + VIRTUALIZATION_TAB) + + # click templates tab + utils.clickIfElementIsVisibleByXpath(self.browser, + TEMPLATES_TAB) + + + # click add template + utils.clickIfElementIsVisibleById(self.browser, + ADD_TEMPLATE) + + # iterate over default templates + utils.waitElementIsVisibleById(self.browser, + ISOS_LIST) + + # retrieve info + info = [] + for template in self.browser.find_elements_by_tag_name("dl"): + info.append([info.text for info in template.find_elements_by_tag_name("dt")]) + return info diff --git a/uiTests/pytest.ini b/uiTests/pytest.ini new file mode 100644 index 000000000..401d96f93 --- /dev/null +++ b/uiTests/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +log_cli = True diff --git a/uiTests/requirements.txt b/uiTests/requirements.txt new file mode 100644 index 000000000..8fac610b9 --- /dev/null +++ b/uiTests/requirements.txt @@ -0,0 +1,28 @@ +appnope==0.1.0 +attrs==19.3.0 +backcall==0.1.0 +chromedriver-binary==78.0.3904.105.0 +decorator==4.4.1 +importlib-metadata==1.3.0 +ipdb==0.12.3 +ipython==7.11.0 +ipython-genutils==0.2.0 +jedi==0.15.2 +more-itertools==8.0.2 +packaging==19.2 +parso==0.5.2 +pexpect==4.7.0 +pickleshare==0.7.5 +pluggy==0.13.1 +prompt-toolkit==3.0.2 +ptyprocess==0.6.0 +py==1.8.1 +Pygments==2.5.2 +pyparsing==2.4.6 +pytest==5.3.2 +selenium==3.141.0 +six==1.13.0 +traitlets==4.3.3 +urllib3==1.25.7 +wcwidth==0.1.7 +zipp==0.6.0 diff --git a/uiTests/test_templates.py b/uiTests/test_templates.py new file mode 100644 index 000000000..5d242945b --- /dev/null +++ b/uiTests/test_templates.py @@ -0,0 +1,31 @@ +import unittest + +from utils import getBrowser +from pages.kimchi_project.templates import KimchiTemplatePage + +EXPECTED_TEMPLATES = [['Fedora', '29', 'Not Available'], + ['Ubuntu', '14.04.6', 'Not Available'], + ['Ubuntu', '14.10', 'Not Available'], + ['Ubuntu', '15.04', 'Not Available'], + ['Ubuntu', '15.10', 'Not Available'], + ['Ubuntu', '16.04.06', 'Not Available'], + ['Gentoo', '20140826', 'Not Available'], + ['Gentoo', '20160514', 'Not Available'] +] + +class TestTemplate(unittest.TestCase): + + def setUp(self): + self.browser = getBrowser() + self.templatePage = KimchiTemplatePage(self.browser) + + def test_default_templates(self): + templates = self.templatePage.retrieveDefaulTemplates() + + # assert templates + for template in templates: + assert template in EXPECTED_TEMPLATES, f"{template} not found" + + def tearDown(self): + self.browser.close() + diff --git a/uiTests/utils.py b/uiTests/utils.py new file mode 100644 index 000000000..285d17a43 --- /dev/null +++ b/uiTests/utils.py @@ -0,0 +1,101 @@ +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support.wait import TimeoutException +from selenium.webdriver.support import expected_conditions as EC + +import chromedriver_binary +import logging +import os + +WAIT = 10 + +def getBrowser(headless=True): + if os.environ.get("DEBUG") is not None: + logging.info("Headless mode deactivated") + headless = False + + options = Options() + if headless is True: + options.add_argument('--headless') + options.add_argument('--no-sandbox') + options.add_argument('--disable-gpu') + + return webdriver.Chrome(options=options) + +def waitElementByCondition(browser, condition, searchMethod, searchString, errorMessage, time=WAIT): + try: + element = WebDriverWait(browser, time).until( + condition((searchMethod, searchString)) + ) + except TimeoutException as e: + logging.error(f"Element {searchString} {errorMessage}") + return False + return True + + +def waitElementIsVisibleById(browser, elementId, time=WAIT): + return waitElementByCondition(browser, + EC.visibility_of_element_located, + By.ID, + elementId, + "is not visibile", + time) + +def waitElementIsVisibleByXpath(browser, xpath): + return waitElementByCondition(browser, + EC.visibility_of_element_located, + By.XPATH, + xpath, + "is not visibile") + +def waitElementIsClickableById(browser, elementId): + return waitElementByCondition(browser, + EC.element_to_be_clickable, + By.ID, + elementId, + "is not clickable") + +def waitElementIsClickableByXpath(browser, xpath): + return waitElementByCondition(browser, + EC.element_to_be_clickable, + By.XPATH, + xpath, + "is not clickable") + +def clickIfElementIsVisibleByXpath(browser, xpath): + try: + assert(waitElementIsVisibleByXpath(browser, xpath)) + assert(waitElementIsClickableByXpath(browser, xpath)) + browser.find_element_by_xpath(xpath).click() + + except Exception as e: + logging.error(f"Cannot click on element {xpath}: {e}") + return False + + return True + +def clickIfElementIsVisibleById(browser, elementId): + try: + assert(waitElementIsVisibleById(browser, elementId)) + assert(waitElementIsClickableById(browser, elementId)) + browser.find_element_by_id(elementId).click() + + except Exception as e: + logging.error(f"Cannot click on element {elementId}: {e}") + return False + + return True + +def fillTextIfElementIsVisibleById(browser, elementId, text): + try: + assert(waitElementIsVisibleById(browser, elementId)) + browser.find_element_by_id(elementId).send_keys(text) + + except Exception as e: + logging.error(f"Cannot type {text} on element {elementId}: {e}") + return False + + return True + From 89ef27e0135bcfe7ee2bd5183c73e80f45e3190d Mon Sep 17 00:00:00 2001 From: Ramon Medeiros Date: Sat, 28 Dec 2019 17:58:45 +0100 Subject: [PATCH 2/6] Add debug instructions --- uiTests/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/uiTests/README.md b/uiTests/README.md index 81b665ecd..680c5b72b 100644 --- a/uiTests/README.md +++ b/uiTests/README.md @@ -21,7 +21,7 @@ $ source .env/bin/activate $ pip install -r requirements.txt ``` -### Run +### Run in headless mode The Makefile expect some environment variables to run kimchi, which are: ``` @@ -35,5 +35,14 @@ KIMCHI_PORT: port for kimchi default: 8001 So, if you are running against a remote host: ``` -$ read -s pass; KIMCHI_HOST= KIMCHI_PASSWORD=$pass make -``` \ No newline at end of file +$ read -s pass; KIMCHI_HOST= KIMCHI_PASSWORD=$pass make +``` + +### Run in debug mode +If you use the command above, the browser will no be visible for you. + +To see the browser action, add the variable `DEBUG` + +``` +$ read -s pass; KIMCHI_HOST= KIMCHI_PASSWORD=$pass DEBUG=true make +``` From 890f82d1c5187afc0f38b199157b5b8d1637154c Mon Sep 17 00:00:00 2001 From: Ramon Medeiros Date: Sat, 28 Dec 2019 18:10:54 +0100 Subject: [PATCH 3/6] Set timeout for page load --- uiTests/pages/kimchi_project/login.py | 15 +++++++++++---- uiTests/utils.py | 4 +++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/uiTests/pages/kimchi_project/login.py b/uiTests/pages/kimchi_project/login.py index 3e3a1ceac..f032f0676 100644 --- a/uiTests/pages/kimchi_project/login.py +++ b/uiTests/pages/kimchi_project/login.py @@ -2,6 +2,8 @@ import os import utils +from selenium.common.exceptions import TimeoutException + # locators by ID USERNAME = "username" PASSWORD = "password" @@ -35,14 +37,19 @@ def __init__(self, browser): assert ENV_HOST in os.environ, f"{ENV_HOST} is a required environment var" # get values - host = os.environ[ENV_HOST] - port = os.environ.get(ENV_PORT) or "8001" + self.host = os.environ[ENV_HOST] + self.port = os.environ.get(ENV_PORT) or "8001" self.user = os.environ[ENV_USER] self.password = os.environ[ENV_PASS] - self.browser.get(f"https://{host}:{port}/login.html") - def login(self): + try: + url = f"https://{self.host}:{self.port}/login.html" + self.browser.get(url) + except TimeoutException as e: + logging.error(f"Cannot reach kimchi at {url}") + return False + # fill user and password utils.fillTextIfElementIsVisibleById(self.browser, USERNAME, diff --git a/uiTests/utils.py b/uiTests/utils.py index 285d17a43..5100ec764 100644 --- a/uiTests/utils.py +++ b/uiTests/utils.py @@ -22,7 +22,9 @@ def getBrowser(headless=True): options.add_argument('--no-sandbox') options.add_argument('--disable-gpu') - return webdriver.Chrome(options=options) + driver = webdriver.Chrome(options=options) + driver.set_page_load_timeout(WAIT * 2) + return driver def waitElementByCondition(browser, condition, searchMethod, searchString, errorMessage, time=WAIT): try: From a905e45566731c8378beec416aa8d051f1f1e458 Mon Sep 17 00:00:00 2001 From: Ramon Medeiros Date: Sun, 19 Jan 2020 14:56:12 +0100 Subject: [PATCH 4/6] Change structure for tests --- .gitignore | 2 +- {uiTests => tests/ui}/README.md | 22 ++-- .../ui/pages}/templates.py | 2 +- tests/ui/pytest.ini | 4 + {uiTests => tests/ui}/requirements.txt | 0 tests/ui/run_tests.sh | 16 +++ tests/ui/test_templates.py | 36 ++++++ uiTests/pages/kimchi_project/login.py | 68 ------------ uiTests/pytest.ini | 2 - uiTests/test_templates.py | 31 ------ uiTests/utils.py | 103 ------------------ 11 files changed, 71 insertions(+), 215 deletions(-) rename {uiTests => tests/ui}/README.md (51%) rename {uiTests/pages/kimchi_project => tests/ui/pages}/templates.py (96%) create mode 100644 tests/ui/pytest.ini rename {uiTests => tests/ui}/requirements.txt (100%) create mode 100755 tests/ui/run_tests.sh create mode 100644 tests/ui/test_templates.py delete mode 100644 uiTests/pages/kimchi_project/login.py delete mode 100644 uiTests/pytest.ini delete mode 100644 uiTests/test_templates.py delete mode 100644 uiTests/utils.py diff --git a/.gitignore b/.gitignore index 9ccf48d54..adf33619b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,4 @@ po/gen-pot *.rej *.pem ui/pages/help/*/*.html -uiTests/.env +tests/ui/.env diff --git a/uiTests/README.md b/tests/ui/README.md similarity index 51% rename from uiTests/README.md rename to tests/ui/README.md index 680c5b72b..20c8b08a5 100644 --- a/uiTests/README.md +++ b/tests/ui/README.md @@ -1,8 +1,8 @@ # Kimchi E2E Tests -The tests are located in uiTests. You should go to the directory to start them +The tests are located in `tests/ui`. You should go to the directory to start them ``` -$ cd uiTests +$ cd tests/ui ``` ## How to run @@ -22,20 +22,22 @@ $ pip install -r requirements.txt ``` ### Run in headless mode -The Makefile expect some environment variables to run kimchi, which are: +The script expect some environment variables to run kimchi-project tests, which are: ``` Expect environment variables: -KIMCHI_USERNAME: username for the host default: root -KIMCHI_PASSWORD: password for the host -KIMCHI_HOST: host for kimchi default: localhost -KIMCHI_PORT: port for kimchi default: 8001 +USERNAME: username for the host default: root +PASSWORD: password for the host +HOST: host for kimchi default: localhost +PORT: port for kimchi default: 8001 ``` So, if you are running against a remote host: ``` -$ read -s pass; KIMCHI_HOST= KIMCHI_PASSWORD=$pass make +$ HOST= ./run_tests.sh +Type password for host USER@HOST + ``` ### Run in debug mode @@ -44,5 +46,7 @@ If you use the command above, the browser will no be visible for you. To see the browser action, add the variable `DEBUG` ``` -$ read -s pass; KIMCHI_HOST= KIMCHI_PASSWORD=$pass DEBUG=true make +$ HOST= DEBUG=true ./run_tests.sh +Type password for host USER@HOST + ``` diff --git a/uiTests/pages/kimchi_project/templates.py b/tests/ui/pages/templates.py similarity index 96% rename from uiTests/pages/kimchi_project/templates.py rename to tests/ui/pages/templates.py index 57bbd4efe..59ad3ee66 100644 --- a/uiTests/pages/kimchi_project/templates.py +++ b/tests/ui/pages/templates.py @@ -1,5 +1,5 @@ import utils -from .login import KimchiLoginPage +from pages.login import KimchiLoginPage VIRTUALIZATION_TAB = "//a[@class = 'item virtualizationTab']" TEMPLATES_TAB = "//a[@href = 'plugins/kimchi/tabs/templates.html']" diff --git a/tests/ui/pytest.ini b/tests/ui/pytest.ini new file mode 100644 index 000000000..1ab51d693 --- /dev/null +++ b/tests/ui/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +verbose = True +log_cli = True +log_cli_level = INFO diff --git a/uiTests/requirements.txt b/tests/ui/requirements.txt similarity index 100% rename from uiTests/requirements.txt rename to tests/ui/requirements.txt diff --git a/tests/ui/run_tests.sh b/tests/ui/run_tests.sh new file mode 100755 index 000000000..85ec8755b --- /dev/null +++ b/tests/ui/run_tests.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +HOST=${HOST:-localhost} +PORT=${PORT:-8001} +USERNAME=${USERNAME:-root} + +# ask for password if not passed +if [ -z $PASSWORD ]; then + echo "Type password for host ${USERNAME}@${HOST}" + read -s PASSWORD +fi + +# ../../../../../../ is wok root + +HOST=${HOST} PASSWORD=${PASSWORD} USERNAME=${USERNAME} PORT=${PORT} \ +PYTHONPATH=$PYTHONPATH:../../../../../../tests/ui/ python3 -m pytest diff --git a/tests/ui/test_templates.py b/tests/ui/test_templates.py new file mode 100644 index 000000000..5a514c1c2 --- /dev/null +++ b/tests/ui/test_templates.py @@ -0,0 +1,36 @@ +import unittest + +from utils import getBrowser +from pages.templates import KimchiTemplatePage +EXPECTED_TEMPLATES = [['Debian', '10', 'Not Available'], + ['Fedora', '30', 'Not Available'], + ['Fedora', '31', 'Not Available'], + ['Opensuse', '15.1', 'Not Available'], + ['Ubuntu', '19.04', 'Not Available'], + ['Ubuntu', '19.10', 'Not Available'] +] + + + +VIRTUALIZATION_TAB = "//a[@class = 'item virtualizationTab']" +TEMPLATES_TAB = "//a[@href = 'plugins/kimchi/tabs/templates.html']" +ADD_TEMPLATE = "template-add" +ISOS_LIST = "list-local-iso" + + +class TestTemplate(unittest.TestCase): + + def setUp(self): + self.browser = getBrowser() + self.templatePage = KimchiTemplatePage(self.browser) + + def test_default_templates(self): + templates = self.templatePage.retrieveDefaulTemplates() + + # assert templates + for template in templates: + assert template in EXPECTED_TEMPLATES, f"{template} not found" + + def tearDown(self): + self.browser.close() + diff --git a/uiTests/pages/kimchi_project/login.py b/uiTests/pages/kimchi_project/login.py deleted file mode 100644 index f032f0676..000000000 --- a/uiTests/pages/kimchi_project/login.py +++ /dev/null @@ -1,68 +0,0 @@ -import logging -import os -import utils - -from selenium.common.exceptions import TimeoutException - -# locators by ID -USERNAME = "username" -PASSWORD = "password" -LOGIN_BUTTON = "btn-login" -LOGIN_BAR = "user-login" - -# environment variables -ENV_USER = "KIMCHI_USERNAME" -ENV_PASS = "KIMCHI_PASSWORD" -ENV_PORT = "KIMCHI_PORT" -ENV_HOST = "KIMCHI_HOST" - - -class KimchiLoginPage(): - """ - Page object to Login - - Expect environment variables: - KIMCHI_USERNAME: username for the host - KIMCHI_PASSWORD: password for the host - KIMCHI_HOST: host for kimchi - KIMCHI_PORT: port for kimchi - """ - - def __init__(self, browser): - self.browser = browser - - # assert envs - assert ENV_USER in os.environ, f"{ENV_USER} is a required environment var" - assert ENV_PASS in os.environ, f"{ENV_PASS} is a required environment var" - assert ENV_HOST in os.environ, f"{ENV_HOST} is a required environment var" - - # get values - self.host = os.environ[ENV_HOST] - self.port = os.environ.get(ENV_PORT) or "8001" - self.user = os.environ[ENV_USER] - self.password = os.environ[ENV_PASS] - - def login(self): - try: - url = f"https://{self.host}:{self.port}/login.html" - self.browser.get(url) - except TimeoutException as e: - logging.error(f"Cannot reach kimchi at {url}") - return False - - # fill user and password - utils.fillTextIfElementIsVisibleById(self.browser, - USERNAME, - self.user) - utils.fillTextIfElementIsVisibleById(self.browser, - PASSWORD, - self.password) - - # press login - utils.clickIfElementIsVisibleById(self.browser, LOGIN_BUTTON) - - # login bar not found: return error - if utils.waitElementIsVisibleById(self.browser, LOGIN_BAR) == False: - logging.error(f"Invalid credentials") - return False - return True diff --git a/uiTests/pytest.ini b/uiTests/pytest.ini deleted file mode 100644 index 401d96f93..000000000 --- a/uiTests/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -log_cli = True diff --git a/uiTests/test_templates.py b/uiTests/test_templates.py deleted file mode 100644 index 5d242945b..000000000 --- a/uiTests/test_templates.py +++ /dev/null @@ -1,31 +0,0 @@ -import unittest - -from utils import getBrowser -from pages.kimchi_project.templates import KimchiTemplatePage - -EXPECTED_TEMPLATES = [['Fedora', '29', 'Not Available'], - ['Ubuntu', '14.04.6', 'Not Available'], - ['Ubuntu', '14.10', 'Not Available'], - ['Ubuntu', '15.04', 'Not Available'], - ['Ubuntu', '15.10', 'Not Available'], - ['Ubuntu', '16.04.06', 'Not Available'], - ['Gentoo', '20140826', 'Not Available'], - ['Gentoo', '20160514', 'Not Available'] -] - -class TestTemplate(unittest.TestCase): - - def setUp(self): - self.browser = getBrowser() - self.templatePage = KimchiTemplatePage(self.browser) - - def test_default_templates(self): - templates = self.templatePage.retrieveDefaulTemplates() - - # assert templates - for template in templates: - assert template in EXPECTED_TEMPLATES, f"{template} not found" - - def tearDown(self): - self.browser.close() - diff --git a/uiTests/utils.py b/uiTests/utils.py deleted file mode 100644 index 5100ec764..000000000 --- a/uiTests/utils.py +++ /dev/null @@ -1,103 +0,0 @@ -from selenium import webdriver -from selenium.webdriver.chrome.options import Options -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support.wait import TimeoutException -from selenium.webdriver.support import expected_conditions as EC - -import chromedriver_binary -import logging -import os - -WAIT = 10 - -def getBrowser(headless=True): - if os.environ.get("DEBUG") is not None: - logging.info("Headless mode deactivated") - headless = False - - options = Options() - if headless is True: - options.add_argument('--headless') - options.add_argument('--no-sandbox') - options.add_argument('--disable-gpu') - - driver = webdriver.Chrome(options=options) - driver.set_page_load_timeout(WAIT * 2) - return driver - -def waitElementByCondition(browser, condition, searchMethod, searchString, errorMessage, time=WAIT): - try: - element = WebDriverWait(browser, time).until( - condition((searchMethod, searchString)) - ) - except TimeoutException as e: - logging.error(f"Element {searchString} {errorMessage}") - return False - return True - - -def waitElementIsVisibleById(browser, elementId, time=WAIT): - return waitElementByCondition(browser, - EC.visibility_of_element_located, - By.ID, - elementId, - "is not visibile", - time) - -def waitElementIsVisibleByXpath(browser, xpath): - return waitElementByCondition(browser, - EC.visibility_of_element_located, - By.XPATH, - xpath, - "is not visibile") - -def waitElementIsClickableById(browser, elementId): - return waitElementByCondition(browser, - EC.element_to_be_clickable, - By.ID, - elementId, - "is not clickable") - -def waitElementIsClickableByXpath(browser, xpath): - return waitElementByCondition(browser, - EC.element_to_be_clickable, - By.XPATH, - xpath, - "is not clickable") - -def clickIfElementIsVisibleByXpath(browser, xpath): - try: - assert(waitElementIsVisibleByXpath(browser, xpath)) - assert(waitElementIsClickableByXpath(browser, xpath)) - browser.find_element_by_xpath(xpath).click() - - except Exception as e: - logging.error(f"Cannot click on element {xpath}: {e}") - return False - - return True - -def clickIfElementIsVisibleById(browser, elementId): - try: - assert(waitElementIsVisibleById(browser, elementId)) - assert(waitElementIsClickableById(browser, elementId)) - browser.find_element_by_id(elementId).click() - - except Exception as e: - logging.error(f"Cannot click on element {elementId}: {e}") - return False - - return True - -def fillTextIfElementIsVisibleById(browser, elementId, text): - try: - assert(waitElementIsVisibleById(browser, elementId)) - browser.find_element_by_id(elementId).send_keys(text) - - except Exception as e: - logging.error(f"Cannot type {text} on element {elementId}: {e}") - return False - - return True - From 4332ca66a926cca52b2ba7b3a00a24a9d796baf4 Mon Sep 17 00:00:00 2001 From: Ramon Medeiros Date: Mon, 20 Jan 2020 10:46:30 +0100 Subject: [PATCH 5/6] Move to pytest fixture --- tests/ui/test_templates.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/ui/test_templates.py b/tests/ui/test_templates.py index 5a514c1c2..d1f7f3996 100644 --- a/tests/ui/test_templates.py +++ b/tests/ui/test_templates.py @@ -1,4 +1,4 @@ -import unittest +import pytest from utils import getBrowser from pages.templates import KimchiTemplatePage @@ -18,19 +18,18 @@ ISOS_LIST = "list-local-iso" -class TestTemplate(unittest.TestCase): +@pytest.fixture() +def templatePage(): + browser = getBrowser() + templatePage = KimchiTemplatePage(browser) + yield templatePage + browser.close() - def setUp(self): - self.browser = getBrowser() - self.templatePage = KimchiTemplatePage(self.browser) +def test_default_templates(templatePage): + templates = templatePage.retrieveDefaulTemplates() - def test_default_templates(self): - templates = self.templatePage.retrieveDefaulTemplates() + # assert templates + for template in templates: + assert template in EXPECTED_TEMPLATES, f"{template} not found" - # assert templates - for template in templates: - assert template in EXPECTED_TEMPLATES, f"{template} not found" - - def tearDown(self): - self.browser.close() From fe89e0bee6226a6791d13ab6c3210a99ea4352bd Mon Sep 17 00:00:00 2001 From: Ramon Medeiros Date: Sun, 26 Jan 2020 23:57:29 +0100 Subject: [PATCH 6/6] Update docs and references to wok --- tests/ui/README.md | 14 ++++++++++++-- tests/ui/pages/templates.py | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/ui/README.md b/tests/ui/README.md index 20c8b08a5..d1e596036 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -21,6 +21,16 @@ $ source .env/bin/activate $ pip install -r requirements.txt ``` +### Install Browser + +This tests expect Google Chrome installed. Visit https://www.google.com/chrome/ for info + +### Start wok server + +``` +$ python src/wokd +``` + ### Run in headless mode The script expect some environment variables to run kimchi-project tests, which are: @@ -28,8 +38,8 @@ The script expect some environment variables to run kimchi-project tests, which Expect environment variables: USERNAME: username for the host default: root PASSWORD: password for the host -HOST: host for kimchi default: localhost -PORT: port for kimchi default: 8001 +HOST: host for wok default: localhost +PORT: port for wok default: 8001 ``` So, if you are running against a remote host: diff --git a/tests/ui/pages/templates.py b/tests/ui/pages/templates.py index 59ad3ee66..97f2a61ee 100644 --- a/tests/ui/pages/templates.py +++ b/tests/ui/pages/templates.py @@ -1,5 +1,5 @@ import utils -from pages.login import KimchiLoginPage +from pages.login import WokLoginPage VIRTUALIZATION_TAB = "//a[@class = 'item virtualizationTab']" TEMPLATES_TAB = "//a[@href = 'plugins/kimchi/tabs/templates.html']" @@ -10,7 +10,7 @@ class KimchiTemplatePage(): def __init__(self, browser): self.browser = browser - assert KimchiLoginPage(browser).login(), "Cannot login to Kimchi" + assert WokLoginPage(browser).login(), "Cannot login to Kimchi" def retrieveDefaulTemplates(self): # click virtualization Tab