summaryrefslogtreecommitdiff
path: root/service/test/functional/features
diff options
context:
space:
mode:
Diffstat (limited to 'service/test/functional/features')
-rw-r--r--service/test/functional/features/account_recovery.feature43
-rw-r--r--service/test/functional/features/environment.py41
-rw-r--r--service/test/functional/features/page_objects/__init__.py20
-rw-r--r--service/test/functional/features/page_objects/account_recovery_page.py57
-rw-r--r--service/test/functional/features/page_objects/backup_account_page.py30
-rw-r--r--service/test/functional/features/page_objects/base_page.py39
-rw-r--r--service/test/functional/features/page_objects/inbox_page.py52
-rw-r--r--service/test/functional/features/smoke.feature8
-rw-r--r--service/test/functional/features/steps/__init__.py2
-rw-r--r--service/test/functional/features/steps/account_recovery.py49
-rw-r--r--service/test/functional/features/steps/backup_account.py20
-rw-r--r--service/test/functional/features/steps/common.py4
-rw-r--r--service/test/functional/features/steps/login.py30
-rw-r--r--service/test/functional/features/steps/mail_list.py18
-rw-r--r--service/test/functional/features/steps/mail_view.py23
-rw-r--r--service/test/functional/features/steps/signup.py21
-rw-r--r--service/test/functional/features/steps/utils.py51
17 files changed, 461 insertions, 47 deletions
diff --git a/service/test/functional/features/account_recovery.feature b/service/test/functional/features/account_recovery.feature
new file mode 100644
index 00000000..da167d31
--- /dev/null
+++ b/service/test/functional/features/account_recovery.feature
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+@smoke @require_user
+Feature: Account Recovery
+ As a user of Pixelated
+ I want to recover my account
+ So that I can see my emails if I lose my password
+
+ Scenario: Sending recovery code
+ Given I am logged in Pixelated
+ When I go to the backup account page
+ And I submit my backup account
+ Then I see the confirmation of this submission
+ And I logout from the header
+ And I should see the login page
+
+ Scenario: Confirming I received the recovery code at my backup email
+ Given I am logged in Pixelated
+ When I open the mail with the recovery code
+ Then I see the mail has the recovery code
+ Then I logout
+
+ Scenario: Recovering an account
+ Given I am on the account recovery page
+ When I submit admin recovery code
+ And I submit user recovery code
+ And I submit new password
+ And I click on the backup account link
+ Then I see the backup account page
diff --git a/service/test/functional/features/environment.py b/service/test/functional/features/environment.py
index 9f8507b2..98c7fa99 100644
--- a/service/test/functional/features/environment.py
+++ b/service/test/functional/features/environment.py
@@ -29,6 +29,8 @@ from pixelated.config.site import PixelatedSite
from pixelated.resources.features_resource import FeaturesResource
from test.support.integration import AppTestClient
from steps.common import DEFAULT_IMPLICIT_WAIT_TIMEOUT_IN_S
+from steps import utils
+from ..page_objects import BackupAccountPage
class UnsuportedWebDriverError(Exception):
@@ -51,19 +53,30 @@ def before_all(context):
if not context.host.startswith('http'):
context.host = 'https://{}'.format(context.host)
- hostname = urlparse(context.host).hostname
- context.signup_url = 'https://{}/signup'.format(hostname)
- context.login_url = 'https://mail.{}/login'.format(hostname)
- context.backup_account_url = 'https://mail.{}/backup-account'.format(hostname)
+ context.hostname = urlparse(context.host).hostname
+ context.signup_url = 'https://{}/signup'.format(context.hostname)
+ context.inbox_url = 'https://mail.{}'.format(context.hostname)
+ context.login_url = 'https://mail.{}/login'.format(context.hostname)
+ context.backup_account_url = 'https://mail.{}/backup-account'.format(context.hostname)
+ context.account_recovery_url = 'https://mail.{}/account-recovery'.format(context.hostname)
context.username = 'testuser_{}'.format(uuid.uuid4())
+ context.user_email = '{}@{}'.format(context.username, context.hostname)
if 'localhost' in context.host:
_mock_user_agent(context)
context.login_url = context.multi_user_url + '/login'
context.backup_account_url = context.single_user_url + '/backup-account'
+ context.account_recovery_url = context.single_user_url + '/account-recovery'
context.username = 'username'
+def before_tag(context, tag):
+ if tag == "require_user":
+ context.username = 'testuser_{}'.format(uuid.uuid4())
+ context.user_email = '{}@{}'.format(context.username, context.hostname)
+ utils.create_user(context)
+
+
def _setup_webdriver(context):
browser = context.config.userdata.get('webdriver', 'chrome')
supported_webdrivers = {
@@ -122,13 +135,24 @@ def after_feature(context, feature):
context.last_mail = None
+def after_scenario(context, scenario):
+ _logout(context)
+ context.browser.refresh()
+
+
def after_step(context, step):
- _debug_on_error(context, step)
- _save_screenshot(context, step)
+ if step.status == 'failed':
+ _debug_on_error(context, step)
+ _save_screenshot(context, step)
+ _logout(context)
+
+
+def _logout(context):
+ context.browser.delete_all_cookies()
def _debug_on_error(context, step):
- if step.status == 'failed' and context.config.userdata.getbool("debug"):
+ if context.config.userdata.getbool("debug"):
try:
import ipdb
ipdb.post_mortem(step.exc_traceback)
@@ -138,8 +162,7 @@ def _debug_on_error(context, step):
def _save_screenshot(context, step):
- if (step.status == 'failed' and
- context.config.userdata.getbool("screenshots", True)):
+ if context.config.userdata.getbool("screenshots", True):
timestamp = time.strftime("%Y-%m-%d-%H-%M-%S")
filename = _slugify('{} failed {}'.format(timestamp, str(step.name)))
filepath = os.path.join('screenshots', filename + '.png')
diff --git a/service/test/functional/features/page_objects/__init__.py b/service/test/functional/features/page_objects/__init__.py
new file mode 100644
index 00000000..af50948c
--- /dev/null
+++ b/service/test/functional/features/page_objects/__init__.py
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from account_recovery_page import AccountRecoveryPage
+from base_page import BasePage
+from inbox_page import InboxPage
+from backup_account_page import BackupAccountPage
diff --git a/service/test/functional/features/page_objects/account_recovery_page.py b/service/test/functional/features/page_objects/account_recovery_page.py
new file mode 100644
index 00000000..8a4e05cd
--- /dev/null
+++ b/service/test/functional/features/page_objects/account_recovery_page.py
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from base_page import BasePage
+
+
+class AccountRecoveryPage(BasePage):
+ def __init__(self, context):
+ super(AccountRecoveryPage, self).__init__(context, context.account_recovery_url)
+
+ self._locators = {
+ 'admin_form': '.account-recovery-form.admin-code',
+ 'admin_code': 'input[name="admin-code"]',
+ 'user_form': '.account-recovery-form.user-code',
+ 'user_code': 'input[name="user-code"]',
+ 'new_password_form': '.account-recovery-form.new-password',
+ 'new_password': 'input[name="new-password"]',
+ 'confirm_password': 'input[name="confirm-password"]',
+ 'submit_button': '.submit-button button[type="submit"]',
+ 'backup_account_link': 'a[href="/backup-account"]'
+ }
+
+ def submit_admin_recovery_code(self, admin_code):
+ self.find_element_by_css_selector(self._locators['admin_form'])
+ self.fill_by_css_selector(self._locators['admin_code'], admin_code)
+ self.click_submit()
+
+ def submit_user_recovery_code(self, user_code):
+ self.find_element_by_css_selector(self._locators['user_form'])
+ self.fill_by_css_selector(self._locators['user_code'], user_code)
+ self.click_submit()
+
+ def submit_new_password(self, new_password, confirm_password):
+ self.find_element_by_css_selector(self._locators['new_password_form'])
+ self.fill_by_css_selector(self._locators['new_password'], new_password)
+ self.fill_by_css_selector(self._locators['confirm_password'], confirm_password)
+ self.click_submit()
+
+ def go_to_backup_account(self):
+ self.find_element_by_css_selector(self._locators['backup_account_link']).click()
+
+ def click_submit(self):
+ submit_button = self.find_element_by_css_selector(self._locators['submit_button'])
+ submit_button.click()
diff --git a/service/test/functional/features/page_objects/backup_account_page.py b/service/test/functional/features/page_objects/backup_account_page.py
new file mode 100644
index 00000000..d5f84b40
--- /dev/null
+++ b/service/test/functional/features/page_objects/backup_account_page.py
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from base_page import BasePage
+
+
+class BackupAccountPage(BasePage):
+ def __init__(self, context):
+ super(BackupAccountPage, self).__init__(context, context.backup_account_url)
+
+ self._locators = {
+ 'logout_button': 'button[name="logout"]'
+ }
+
+ def logout(self):
+ logout_button = self.find_element_by_css_selector(self._locators['logout_button'])
+ logout_button.click()
diff --git a/service/test/functional/features/page_objects/base_page.py b/service/test/functional/features/page_objects/base_page.py
new file mode 100644
index 00000000..4756d930
--- /dev/null
+++ b/service/test/functional/features/page_objects/base_page.py
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from steps.common import (
+ fill_by_css_selector,
+ find_element_by_css_selector,
+ find_element_by_xpath)
+
+
+class BasePage(object):
+ def __init__(self, context, base_url):
+ self.context = context
+ self.timeout = 30
+ self.base_url = base_url
+
+ def find_element_by_css_selector(self, loc):
+ return find_element_by_css_selector(self.context, loc)
+
+ def fill_by_css_selector(self, loc, text):
+ fill_by_css_selector(self.context, loc, text)
+
+ def find_element_by_xpath(self, xpath):
+ return find_element_by_xpath(self.context, xpath)
+
+ def visit(self):
+ self.context.browser.get(self.base_url)
diff --git a/service/test/functional/features/page_objects/inbox_page.py b/service/test/functional/features/page_objects/inbox_page.py
new file mode 100644
index 00000000..a6b5fef7
--- /dev/null
+++ b/service/test/functional/features/page_objects/inbox_page.py
@@ -0,0 +1,52 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from base_page import BasePage
+from steps.common import execute_ignoring_staleness
+
+
+class InboxPage(BasePage):
+ def __init__(self, context):
+ super(InboxPage, self).__init__(context, context.inbox_url)
+
+ self._locators = {
+ 'first_email': '.mail-list-entry__item',
+ 'read_sandbox': '#read-sandbox',
+ 'iframe_body': 'body',
+ }
+
+ def _get_first_mail(self):
+ return self.find_element_by_css_selector(self._locators['first_email'])
+
+ def get_mail_with_subject(self, subject):
+ return self.find_element_by_xpath("//*[@class='mail-list-entry__item-subject' and contains(.,'%s')]" % subject)
+
+ def open_first_mail_in_the_mail_list(self):
+ # it seems page is often still loading so staleness exceptions happen often
+ self.context.current_mail_id = 'mail-' + execute_ignoring_staleness(
+ lambda: self._get_first_mail().get_attribute('href').split('/')[-1])
+ execute_ignoring_staleness(lambda: self._get_first_mail().click())
+
+ def open_mail_with_the_recovery_code(self):
+ self.get_mail_with_subject('Recovery Code').click()
+
+ def get_body_message(self):
+ self.find_element_by_css_selector(self._locators['read_sandbox'])
+ self.context.browser.switch_to_frame('read-sandbox')
+ body_message = self.find_element_by_css_selector(self._locators['iframe_body']).text
+ self.context.browser.switch_to_default_content()
+
+ return body_message
diff --git a/service/test/functional/features/smoke.feature b/service/test/functional/features/smoke.feature
index 1467baf9..d4149334 100644
--- a/service/test/functional/features/smoke.feature
+++ b/service/test/functional/features/smoke.feature
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-@smoke
+@smoke @require_user
Feature: sign up, login and logout
As a visitor of Pixelated
I want to sign up
@@ -31,7 +31,8 @@ Feature: sign up, login and logout
When I enter username and password as credentials
And I click on the login button
Then I should see the fancy interstitial
- Then I have mails
+ And I should see the inbox
+ And I have mails
When I logout
Then I should see the login page
@@ -40,6 +41,7 @@ Feature: sign up, login and logout
When I enter username and password as credentials
And I click on the login button
Then I should see the fancy interstitial
- Given I am on the backup account page
+ And I should see the inbox
+ Given I go to the backup account page
When I logout from the header
Then I should see the login page
diff --git a/service/test/functional/features/steps/__init__.py b/service/test/functional/features/steps/__init__.py
index 2756a319..5750dc53 100644
--- a/service/test/functional/features/steps/__init__.py
+++ b/service/test/functional/features/steps/__init__.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014 ThoughtWorks, Inc.
+# Copyright (c) 2017 ThoughtWorks, Inc.
#
# Pixelated is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
diff --git a/service/test/functional/features/steps/account_recovery.py b/service/test/functional/features/steps/account_recovery.py
new file mode 100644
index 00000000..ac66cf76
--- /dev/null
+++ b/service/test/functional/features/steps/account_recovery.py
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2017 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from behave import given, when, then
+
+from ..page_objects import AccountRecoveryPage
+
+
+@given(u'I am on the account recovery page')
+def account_recovery_page(context):
+ AccountRecoveryPage(context).visit()
+
+
+@when(u'I submit admin recovery code')
+def submit_admin_recovery_code(context):
+ AccountRecoveryPage(context).submit_admin_recovery_code('1234')
+
+
+@when(u'I submit user recovery code')
+def submit_user_recovery_code(context):
+ AccountRecoveryPage(context).submit_user_recovery_code('5678')
+
+
+@when(u'I submit new password')
+def submit_new_password(context):
+ AccountRecoveryPage(context).submit_new_password('new test password', 'new test password')
+
+
+@when(u'I click on the backup account link')
+def go_to_backup_account(context):
+ AccountRecoveryPage(context).go_to_backup_account()
+
+
+@then(u'I see the backup account page')
+def verify_backup_account_page(context):
+ assert('/backup-account' in context.browser.current_url)
diff --git a/service/test/functional/features/steps/backup_account.py b/service/test/functional/features/steps/backup_account.py
index 914309f2..5a1052a8 100644
--- a/service/test/functional/features/steps/backup_account.py
+++ b/service/test/functional/features/steps/backup_account.py
@@ -14,9 +14,25 @@
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-from behave import given
+from behave import given, when, then
+from common import (
+ fill_by_css_selector,
+ find_element_by_css_selector)
-@given(u'I am on the backup account page')
+
+@when(u'I go to the backup account page')
+@given(u'I go to the backup account page')
def backup_account_page(context):
context.browser.get(context.backup_account_url)
+
+
+@when(u'I submit my backup account')
+def submit_backup_email(context):
+ fill_by_css_selector(context, 'input[name="email"]', context.user_email)
+ find_element_by_css_selector(context, '.submit-button button[type="submit"]').click()
+
+
+@then(u'I see the confirmation of this submission')
+def confirmation_page(context):
+ find_element_by_css_selector(context, '.confirmation-container', timeout=50)
diff --git a/service/test/functional/features/steps/common.py b/service/test/functional/features/steps/common.py
index 3e1e995e..ff6e6166 100644
--- a/service/test/functional/features/steps/common.py
+++ b/service/test/functional/features/steps/common.py
@@ -146,10 +146,6 @@ def click_button(context, title, element='button'):
button.click()
-def mail_list_with_subject_exists(context, subject):
- return find_element_by_xpath(context, "//*[@class='mail-list-entry__item-subject' and contains(.,'%s')]" % subject)
-
-
def reply_subject(context):
e = find_element_by_css_selector(context, '#reply-subject')
return e.text
diff --git a/service/test/functional/features/steps/login.py b/service/test/functional/features/steps/login.py
index 2d7be259..0ac27c46 100644
--- a/service/test/functional/features/steps/login.py
+++ b/service/test/functional/features/steps/login.py
@@ -21,16 +21,29 @@ from common import (
find_element_by_css_selector)
+@given('I am logged in Pixelated')
+def login_user(context):
+ login_page(context)
+ enter_credentials(context)
+ click_login(context)
+ see_interstitial(context)
+ _see_inbox(context)
+
+
@given(u'a user is accessing the login page')
@when(u'I open the login page')
def login_page(context):
context.browser.get(context.login_url)
-@when(u'I enter {username} and {password} as credentials')
-def enter_credentials(context, username, password):
+def _see_inbox(context):
+ find_element_by_css_selector(context, '#compose', timeout=40)
+
+
+@when(u'I enter username and password as credentials')
+def enter_credentials(context):
fill_by_css_selector(context, 'input[name="username"]', context.username)
- fill_by_css_selector(context, 'input[name="password"]', password)
+ fill_by_css_selector(context, 'input[name="password"]', 'password')
@when(u'I click on the login button')
@@ -39,20 +52,29 @@ def click_login(context):
@then(u'I should see the fancy interstitial')
-def step_impl(context):
+def see_interstitial(context):
find_element_by_css_selector(context, 'section#hive-section')
+@then(u'I should see the inbox')
+def see_inbox(context):
+ _see_inbox(context)
+
+
+@then(u'I logout')
@when(u'I logout')
def click_logout(context):
+ context.browser.refresh()
find_element_by_css_selector(context, '#logout-form div').click()
+@then(u'I logout from the header') # noqa
@when(u'I logout from the header')
def click_logout(context):
find_element_by_css_selector(context, 'button[name="logout"]').click()
+@when(u'I should see the login page')
@then(u'I should see the login page')
def see_login_page(context):
find_element_by_css_selector(context, 'form#login_form')
diff --git a/service/test/functional/features/steps/mail_list.py b/service/test/functional/features/steps/mail_list.py
index 227aa9ed..21694153 100644
--- a/service/test/functional/features/steps/mail_list.py
+++ b/service/test/functional/features/steps/mail_list.py
@@ -17,13 +17,12 @@
from behave import when, then, given
from selenium.common.exceptions import TimeoutException
+from ..page_objects import InboxPage
from common import (
ImplicitWait,
- execute_ignoring_staleness,
find_element_by_id,
find_element_by_css_selector,
find_elements_by_css_selector,
- mail_list_with_subject_exists,
wait_for_condition,
wait_for_loading_to_finish)
@@ -42,10 +41,6 @@ def open_current_mail(context):
e.click()
-def get_first_email(context):
- return find_element_by_css_selector(context, '.mail-list-entry__item')
-
-
@then('I see that mail under the \'{tag}\' tag')
def impl(context, tag):
context.execute_steps("when I select the tag '%s'" % tag)
@@ -59,9 +54,12 @@ def impl(context):
@when('I open the first mail in the mail list')
def impl(context):
- # it seems page is often still loading so staleness exceptions happen often
- context.current_mail_id = 'mail-' + execute_ignoring_staleness(lambda: get_first_email(context).get_attribute('href').split('/')[-1])
- execute_ignoring_staleness(lambda: get_first_email(context).click())
+ InboxPage(context).open_first_mail_in_the_mail_list()
+
+
+@when('I open the mail with the recovery code')
+def impl(context):
+ InboxPage(context).open_mail_with_the_recovery_code()
@when('I open the first mail in the \'{tag}\'')
@@ -83,7 +81,7 @@ def impl(context):
@then('the deleted mail is there')
def impl(context):
- mail_list_with_subject_exists(context, context.last_subject)
+ InboxPage(context).get_mail_with_subject(context.last_subject)
@given('I have mails')
diff --git a/service/test/functional/features/steps/mail_view.py b/service/test/functional/features/steps/mail_view.py
index 65959b70..26368aaa 100644
--- a/service/test/functional/features/steps/mail_view.py
+++ b/service/test/functional/features/steps/mail_view.py
@@ -17,6 +17,7 @@
from behave import then, when
from selenium.webdriver.common.keys import Keys
+from ..page_objects import InboxPage
from common import (
click_button,
find_element_by_css_selector,
@@ -25,19 +26,17 @@ from common import (
wait_until_button_is_visible)
-@then('I see that the subject reads \'{subject}\'')
-def impl(context, subject):
- e = find_element_by_css_selector(context, '#mail-view .mail-read-view__header-subject')
- assert e.text == subject
+@then('I see that the subject reads \'{expected_subject}\'')
+def impl(context, expected_subject):
+ actual_subject = find_element_by_css_selector(context, '#mail-view .mail-read-view__header-subject').text
+ assert expected_subject == actual_subject
@then('I see that the body reads \'{expected_body}\'')
+@then('I see that the body has \'{expected_body}\'')
def impl(context, expected_body):
- find_element_by_css_selector(context, '#read-sandbox')
- context.browser.switch_to_frame('read-sandbox')
- e = find_element_by_css_selector(context, 'body')
- assert e.text == expected_body
- context.browser.switch_to_default_content()
+ actual_body = InboxPage(context).get_body_message()
+ assert expected_body in actual_body
@then('that email has the \'{tag}\' tag')
@@ -110,3 +109,9 @@ def impl(context):
assert cc is not None
assert bcc is not None
+
+
+@then(u'I see the mail has the recovery code')
+def step_impl(context):
+ expected_body = 'You are receiving this message because you registered an email account at'
+ context.execute_steps(u"Then I see that the body has '%s'" % expected_body)
diff --git a/service/test/functional/features/steps/signup.py b/service/test/functional/features/steps/signup.py
index 43480666..71df1868 100644
--- a/service/test/functional/features/steps/signup.py
+++ b/service/test/functional/features/steps/signup.py
@@ -14,6 +14,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+import uuid
+
from behave import given, then, when
from common import (
@@ -23,22 +25,31 @@ from common import (
@given(u'a user is accessing the signup page') # noqa
-def step_impl(context):
+def access_signup_page(context):
context.browser.get(context.signup_url)
+@given(u'I am an existent Pixelated user')
+def setup_user(context):
+ access_signup_page(context)
+ enter_user_information(context)
+ click_signup_button(context)
+ see_user_control_panel(context)
+
+
@when(u'I enter username, password and password confirmation') # noqa
-def step_impl(context):
- fill_by_css_selector(context, '#srp_username', context.username)
+def enter_user_information(context):
+ username = 'testuser_{}'.format(uuid.uuid4())
+ fill_by_css_selector(context, '#srp_username', username)
fill_by_css_selector(context, '#srp_password', 'password')
fill_by_css_selector(context, '#srp_password_confirmation', 'password')
@when(u'I click on the signup button') # noqa
-def step_impl(context):
+def click_signup_button(context):
find_element_by_css_selector(context, 'button[type=submit]').click()
@then(u'I should see the user control panel') # noqa
-def step_impl(context):
+def see_user_control_panel(context):
element_should_have_content(context, 'h1', 'user control panel')
diff --git a/service/test/functional/features/steps/utils.py b/service/test/functional/features/steps/utils.py
new file mode 100644
index 00000000..9ac05928
--- /dev/null
+++ b/service/test/functional/features/steps/utils.py
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2016 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+from common import (
+ element_should_have_content,
+ fill_by_css_selector,
+ find_element_by_css_selector)
+
+
+def access_signup_page(context):
+ context.browser.get(context.signup_url)
+
+
+def create_user(context):
+ context.browser.get(context.login_url)
+ access_signup_page(context)
+ enter_user_information(context)
+ click_signup_button(context)
+ see_user_control_panel(context)
+ log_out(context)
+
+
+def log_out(context):
+ find_element_by_css_selector(context, 'a[href="/logout"]').click()
+
+
+def enter_user_information(context):
+ fill_by_css_selector(context, '#srp_username', context.username)
+ fill_by_css_selector(context, '#srp_password', 'password')
+ fill_by_css_selector(context, '#srp_password_confirmation', 'password')
+
+
+def click_signup_button(context):
+ find_element_by_css_selector(context, 'button[type=submit]').click()
+
+
+def see_user_control_panel(context):
+ element_should_have_content(context, 'h1', 'user control panel')