diff options
author | Varac <varac@leap.se> | 2017-06-09 09:40:55 +0200 |
---|---|---|
committer | Azul <azul@riseup.net> | 2017-07-20 12:34:33 +0200 |
commit | d6abd906cb64ae68eed3348eba521bc44ebed7b2 (patch) | |
tree | fadf7d8270106a628c31b1f7017f343a94f311f0 /tests/functional/features/steps | |
parent | c81b98df15e3d2006c991c9ca9d86500e3599e9b (diff) |
[test] Add basic functional login test
* Move todo list to https://0xacab.org/leap/bitmask-dev/issues/8929
* use bundled pysqlcipher - debian package has not been fixed yet.
* reset bitmaskd for each scenario so they are isolated
* run functional tests on CI
* moved e2e tests before the bundle
* add test_functional_graphical Make target
* Install chromedriver in docker image
* add screenshots as artifacts on failure
* run chrome without sandbox for docker
Tests were failing on CI with chrome sandbox:
https://0xacab.org/leap/bitmask-dev/-/jobs/15196
Used this workaround:
https://stackoverflow.com/questions/28364012/webdriver-exception-chrome-not-reachable/28949227#28949227
- Resolves: #8929
Diffstat (limited to 'tests/functional/features/steps')
-rw-r--r-- | tests/functional/features/steps/bitmask.py | 26 | ||||
-rw-r--r-- | tests/functional/features/steps/common.py | 138 | ||||
-rw-r--r-- | tests/functional/features/steps/login.py | 45 |
3 files changed, 209 insertions, 0 deletions
diff --git a/tests/functional/features/steps/bitmask.py b/tests/functional/features/steps/bitmask.py new file mode 100644 index 0000000..b5b4cf1 --- /dev/null +++ b/tests/functional/features/steps/bitmask.py @@ -0,0 +1,26 @@ +import commands +import shutil +import os +import time +from leap.common.config import get_path_prefix + +from behave import given + + +@given('I start bitmask for the first time') +def initial_run(context): + commands.getoutput('bitmaskctl stop') + # TODO: fix bitmaskctl to only exit once bitmaskd has stopped + time.sleep(2) + _initialize_home_path() + commands.getoutput('bitmaskctl start') + tokenpath = os.path.join(get_path_prefix(), 'leap', 'authtoken') + token = open(tokenpath).read().strip() + context.login_url = "http://localhost:7070/#%s" % token + + +def _initialize_home_path(): + home_path = '/tmp/bitmask-test' + shutil.rmtree(home_path, ignore_errors=True) + os.environ['HOME'] = home_path + os.makedirs(get_path_prefix()) diff --git a/tests/functional/features/steps/common.py b/tests/functional/features/steps/common.py new file mode 100644 index 0000000..91858f8 --- /dev/null +++ b/tests/functional/features/steps/common.py @@ -0,0 +1,138 @@ +import time + +from selenium.common.exceptions import ( + StaleElementReferenceException, + TimeoutException) +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.wait import WebDriverWait + +TIMEOUT_IN_S = 10 + +DEFAULT_IMPLICIT_WAIT_TIMEOUT_IN_S = 10 + + +def wait_until_element_is_invisible_by_locator(context, locator_tuple, + timeout=TIMEOUT_IN_S): + wait = WebDriverWait(context.browser, timeout) + wait.until(EC.invisibility_of_element_located(locator_tuple)) + + +def wait_for_loading_to_finish(context, timeout=TIMEOUT_IN_S): + wait_until_element_is_invisible_by_locator( + context, (By.ID, 'loading'), timeout) + + +def wait_for_user_alert_to_disapear(context, timeout=TIMEOUT_IN_S): + wait_until_element_is_invisible_by_locator( + context, (By.ID, 'user-alerts'), timeout) + + +def _wait_until_elements_are_visible_by_locator(context, locator_tuple, + timeout=TIMEOUT_IN_S): + wait = WebDriverWait(context.browser, timeout) + wait.until(EC.presence_of_all_elements_located(locator_tuple)) + return context.browser.find_elements(locator_tuple[0], locator_tuple[1]) + + +def _wait_until_element_is_visible_by_locator(context, locator_tuple, + timeout=TIMEOUT_IN_S): + wait = WebDriverWait(context.browser, timeout) + wait.until(EC.visibility_of_element_located(locator_tuple)) + return context.browser.find_element(locator_tuple[0], locator_tuple[1]) + + +def wait_for_condition(context, predicate_func, timeout=TIMEOUT_IN_S, + poll_frequency=0.1): + wait = WebDriverWait(context.browser, timeout, + poll_frequency=poll_frequency) + wait.until(predicate_func) + + +def fill_by_xpath(context, xpath, text): + field = context.browser.find_element_by_xpath(xpath) + field.send_keys(text) + + +def fill_by_css_selector(context, css_selector, text, timeout=TIMEOUT_IN_S): + field = find_element_by_css_selector(context, css_selector, + timeout=timeout) + field.send_keys(text) + + +def take_screenshot(context, filename): + context.browser.save_screenshot(filename) + + +def page_has_css(context, css): + try: + find_element_by_css_selector(context, css) + return True + except TimeoutException: + return False + + +def find_element_by_xpath(context, xpath): + return _wait_until_element_is_visible_by_locator( + context, (By.XPATH, xpath)) + + +def find_element_by_id(context, id): + return _wait_until_element_is_visible_by_locator(context, (By.ID, id)) + + +def find_element_by_css_selector(context, css_selector, timeout=TIMEOUT_IN_S): + return _wait_until_element_is_visible_by_locator( + context, (By.CSS_SELECTOR, css_selector), timeout=timeout) + + +def find_element_by_class_name(context, class_name): + return _wait_until_element_is_visible_by_locator( + context, (By.CLASS_NAME, class_name)) + + +def find_elements_by_css_selector(context, css_selector, timeout=TIMEOUT_IN_S): + return _wait_until_elements_are_visible_by_locator( + context, (By.CSS_SELECTOR, css_selector), timeout=timeout) + + +def find_elements_by_xpath(context, xpath, timeout=TIMEOUT_IN_S): + return _wait_until_elements_are_visible_by_locator( + context, (By.XPATH, xpath), timeout=timeout) + + +def find_element_containing_text(context, text, element_type='*'): + return find_element_by_xpath( + context, "//%s[contains(.,'%s')]" % (element_type, text)) + + +def element_should_have_content(context, css_selector, content): + e = find_element_by_css_selector(context, css_selector) + assert e.text == content + + +def wait_until_button_is_visible(context, title, timeout=TIMEOUT_IN_S): + wait = WebDriverWait(context.browser, timeout) + locator_tuple = (By.XPATH, ("//%s[contains(.,'%s')]" % ('button', title))) + wait.until(EC.visibility_of_element_located(locator_tuple)) + + +def execute_ignoring_staleness(func, timeout=TIMEOUT_IN_S): + end_time = time.time() + timeout + while time.time() <= end_time: + try: + return func() + except StaleElementReferenceException: + pass + raise TimeoutException( + 'did not solve stale state until timeout %f' % timeout) + + +def click_button(context, title, element='button'): + button = find_element_containing_text(context, title, element_type=element) + button.click() + + +def reply_subject(context): + e = find_element_by_css_selector(context, '#reply-subject') + return e.text diff --git a/tests/functional/features/steps/login.py b/tests/functional/features/steps/login.py new file mode 100644 index 0000000..4a5981a --- /dev/null +++ b/tests/functional/features/steps/login.py @@ -0,0 +1,45 @@ +from behave import given, when, then + +from common import ( + click_button, + fill_by_css_selector, + find_element_by_css_selector +) + + +@when(u'I login') +def login_user(context): + login_page(context) + enter_credentials(context) + click_button(context, 'Log In') + + +def login_page(context): + context.browser.get(context.login_url) + context.browser.refresh() + + +def enter_credentials(context): + fill_by_css_selector(context, 'textarea[id="loginUsername"]', + context.username) + fill_by_css_selector(context, 'input[id="loginPassword"]', + context.password) + + +@then(u'I should see the user panel') +def see_home_screen(context): + find_element_by_css_selector(context, '.main-panel') + + +@then(u'I logout') +@when(u'I logout') +def click_logout(context): + # TODO: Have identifiers for the "second" login screen + click_button(context, 'Log Out') + + +@then(u'I should see the second login page') +def see_second_login_page(context): + # TODO: Have unique identifiers for the second login page + # (that differentiates from user panel) + find_element_by_css_selector(context, '#loginUsername') |