diff --git a/automation-tests/browserid/.gitignore b/automation-tests/browserid/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..c1c3e1d2badf37f9f939493b88913eee6e521e18 --- /dev/null +++ b/automation-tests/browserid/.gitignore @@ -0,0 +1,4 @@ +*.pyc +*.komodoproject +build +results diff --git a/automation-tests/browserid/.travis.yml b/automation-tests/browserid/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..89d46cb5070cca8418940f3cf71b558ba484e945 --- /dev/null +++ b/automation-tests/browserid/.travis.yml @@ -0,0 +1,19 @@ +before_script: + - sh -e /etc/init.d/xvfb start + +language: python +python: + - 2.6 + - 2.7 + +script: py.test --baseurl=http://dev.123done.org --driver=firefox -m travis tests + +env: + - DISPLAY=':99.0' + +notifications: + email: + - dave.hunt@gmail.com + irc: + - "irc.mozilla.org#automation" + - "irc.mozilla.org#identity" diff --git a/automation-tests/browserid/README.md b/automation-tests/browserid/README.md new file mode 100644 index 0000000000000000000000000000000000000000..df702c27ced028d9a83ae20ef4494914525b6b7a --- /dev/null +++ b/automation-tests/browserid/README.md @@ -0,0 +1,15 @@ +**B**rowser**ID** **P**age **O**bject **M**odel +=============================================== +Selenium compatible page object model for Mozilla's BrowserID. + +Documentation +------------- +See the project's [wiki](https://github.com/mozilla/bidpom/wiki). + +License +------- +This software is licensed under the [MPL](http://www.mozilla.org/MPL/2.0/) 2.0: + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/automation-tests/browserid/__init__.py b/automation-tests/browserid/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..087f0766badd9866e8596230707814a76a96ac1f --- /dev/null +++ b/automation-tests/browserid/__init__.py @@ -0,0 +1 @@ +from browser_id import BrowserID diff --git a/automation-tests/browserid/browser_id.py b/automation-tests/browserid/browser_id.py new file mode 100644 index 0000000000000000000000000000000000000000..21aea5ebce650d688cc8c32e64b05373c47c9e87 --- /dev/null +++ b/automation-tests/browserid/browser_id.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import selenium + + +class BrowserID(object): + + VERIFY_URL_REGEX = 'https?:\/\/(\S+)\/verify_email_address\?token=(.{48})' + CONFIRM_URL_REGEX = 'https?:\/\/(\S+)\/confirm\?token=(.{48})' + RESET_URL_REGEX = 'https?:\/\/(\S+)\/reset_password\?token=(.{48})' + INCLUDE_URL_REGEX = '(https?:\/\/(\S+))\/include\.js' + + def __init__(self, selenium, timeout=60): + self.selenium = selenium + self.timeout = timeout + + def sign_in(self, email, password): + """Signs in using the specified email address and password.""" + from pages.sign_in import SignIn + sign_in = SignIn(self.selenium, timeout=self.timeout, expect='new') + sign_in.sign_in(email, password) diff --git a/automation-tests/browserid/conftest.py b/automation-tests/browserid/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..048e3efc767ae0bf352ece75fefde1ebc9d8a265 --- /dev/null +++ b/automation-tests/browserid/conftest.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import py + + +def pytest_runtest_setup(item): + pytest_mozwebqa = py.test.config.pluginmanager.getplugin('mozwebqa') + pytest_mozwebqa.TestSetup.email = item.config.option.email + pytest_mozwebqa.TestSetup.password = item.config.option.password + + +def pytest_addoption(parser): + group = parser.getgroup('persona', 'persona') + group._addoption('--email', + action='store', + metavar='str', + help='email address for persona account') + group._addoption('--password', + action='store', + metavar='str', + help='password for persona account') + + +def pytest_funcarg__mozwebqa(request): + return request.getfuncargvalue('mozwebqa') diff --git a/automation-tests/browserid/mocks/__init__.py b/automation-tests/browserid/mocks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/automation-tests/browserid/mocks/user.py b/automation-tests/browserid/mocks/user.py new file mode 100644 index 0000000000000000000000000000000000000000..8be1e3bfd9a2b390989be5cd4cec9552e27e4e2b --- /dev/null +++ b/automation-tests/browserid/mocks/user.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import uuid + + +class MockUser(dict): + + def __init__(self, **kwargs): + self['id'] = 'bidpom_%s' % uuid.uuid1() + self['primary_email'] = '%s@restmail.net' % self.id + self['password'] = 'password' + self['additional_emails'] = [] + + self.update(**kwargs) + + def __getattr__(self, attr): + return self[attr] diff --git a/automation-tests/browserid/mozwebqa.cfg b/automation-tests/browserid/mozwebqa.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8b6ad1effcda45be9e2f84987c804c5d56f21eec --- /dev/null +++ b/automation-tests/browserid/mozwebqa.cfg @@ -0,0 +1,3 @@ +[DEFAULT] +baseurl = http://123done.org +tags = bidpom diff --git a/automation-tests/browserid/pages/__init__.py b/automation-tests/browserid/pages/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/automation-tests/browserid/pages/account_manager.py b/automation-tests/browserid/pages/account_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..0428acd806d1a3d5efe2a357da802e53654085b3 --- /dev/null +++ b/automation-tests/browserid/pages/account_manager.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from base import Base + +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait + + +class AccountManager(Base): + + _emails_locator = (By.CSS_SELECTOR, '#emailList .email') + _edit_password_button_locator = (By.CSS_SELECTOR, '#edit_password button.edit') + _old_password_field_locator = (By.ID, 'old_password') + _new_password_field_locator = (By.ID, 'new_password') + _change_password_done_locator = (By.ID, 'changePassword') + _sign_in_locator = (By.CSS_SELECTOR, 'a.signIn') + _sign_out_locator = (By.CSS_SELECTOR, 'a.signOut') + + def __init__(self, selenium, timeout): + Base.__init__(self, selenium, timeout) + + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._emails_locator).is_displayed()) + + @property + def signed_in(self): + return 'not_authenticated' not in self.selenium.find_element(By.TAG_NAME, 'body').get_attribute('class') + + @property + def emails(self): + return [element.text for element in self.selenium.find_elements(*self._emails_locator)] + + def click_edit_password(self): + """Click edit password to show the new/old password fields""" + self.selenium.find_element(*self._edit_password_button_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._old_password_field_locator).is_displayed()) + + @property + def old_password(self): + """Get the value of the old password field.""" + return self.selenium.find_element(*self._old_password_field_locator).text + + @old_password.setter + def old_password(self, value): + """Set the value of the old password field.""" + password = self.selenium.find_element(*self._old_password_field_locator) + password.clear() + password.send_keys(value) + + @property + def new_password(self): + """Get the value of the new password field.""" + return self.selenium.find_element(*self._new_password_field_locator).text + + @new_password.setter + def new_password(self, value): + """Set the value of the new password field.""" + password = self.selenium.find_element(*self._new_password_field_locator) + password.clear() + password.send_keys(value) + + def click_password_done(self): + """Click password done to save the new password.""" + self.selenium.find_element(*self._change_password_done_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._edit_password_button_locator).is_displayed()) + + def click_sign_out(self): + self.selenium.find_element(*self._sign_out_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: not self.signed_in) diff --git a/automation-tests/browserid/pages/base.py b/automation-tests/browserid/pages/base.py new file mode 100644 index 0000000000000000000000000000000000000000..e8cd99b7bf7ec042cfafafe60fc043dbfbcf5edd --- /dev/null +++ b/automation-tests/browserid/pages/base.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +class Base(object): + + _page_title = 'Mozilla Persona: A Better Way to Sign In' + + def __init__(self, selenium, timeout=60): + self.selenium = selenium + self.timeout = timeout + self._main_window_handle = self.selenium.current_window_handle + + def switch_to_main_window(self): + self.selenium.switch_to_window(self._main_window_handle) diff --git a/automation-tests/browserid/pages/complete_registration.py b/automation-tests/browserid/pages/complete_registration.py new file mode 100644 index 0000000000000000000000000000000000000000..141c1ea1fe33a2e89594cc6d625ab34d85423d83 --- /dev/null +++ b/automation-tests/browserid/pages/complete_registration.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from base import Base + +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait + + +class CompleteRegistration(Base): + + _email_locator = (By.ID, 'email') + _password_locator = (By.ID, 'password') + _finish_locator = (By.CSS_SELECTOR, 'div.submit > button') + _thank_you_locator = (By.ID, 'congrats') + + def __init__(self, selenium, timeout, expect='success'): + Base.__init__(self, selenium, timeout) + + if expect == 'success': + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._thank_you_locator).is_displayed()) + elif expect == 'verify': + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._password_locator).is_displayed()) + else: + raise Exception('Unknown expect value: %s' % expect) + + @property + def email(self): + """Get the value of the email field.""" + return self.selenium.find_element(*self._email_locator).text + + @property + def password(self): + """Get the value of the password field.""" + return self.selenium.find_element(*self._password_locator).text + + @password.setter + def password(self, value): + """Set the value of the password field.""" + password = self.selenium.find_element(*self._password_locator) + password.clear() + password.send_keys(value) + + def click_finish(self): + """Clicks the 'finish' button.""" + self.selenium.find_element(*self._finish_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._thank_you_locator).is_displayed()) + + @property + def thank_you(self): + """Returns the 'thank you' message.""" + return self.selenium.find_element(*self._thank_you_locator).text diff --git a/automation-tests/browserid/pages/sign_in.py b/automation-tests/browserid/pages/sign_in.py new file mode 100644 index 0000000000000000000000000000000000000000..2a22a4a435b8b26d8d2b625bb449130253917475 --- /dev/null +++ b/automation-tests/browserid/pages/sign_in.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from base import Base + +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait + + +class SignIn(Base): + + _this_is_not_me_locator = (By.ID, 'thisIsNotMe') + _signed_in_email_locator = (By.CSS_SELECTOR, 'label[for=email_0]') + _emails_locator = (By.CSS_SELECTOR, 'label[for^=email_]') + _email_locator = (By.ID, 'email') + _password_locator = (By.ID, 'password') + _verify_password_locator = (By.ID, 'vpassword') + _next_locator = (By.CSS_SELECTOR, 'button.start') + _sign_in_locator = (By.CSS_SELECTOR, 'button.returning') + _sign_in_returning_user_locator = (By.ID, 'signInButton') + _verify_email_locator = (By.ID, 'verify_user') + _forgot_password_locator = (By.ID, 'forgotPassword') + _reset_password_locator = (By.ID, 'password_reset') + _check_email_at_locator = (By.CSS_SELECTOR, '#wait .contents h2 + p strong') + _add_another_email_locator = (By.ID, 'useNewEmail') + _new_email_locator = (By.ID, 'newEmail') + _add_new_email_locator = (By.ID, 'addNewEmail') + + def __init__(self, selenium, timeout, expect='new'): + Base.__init__(self, selenium, timeout) + + if self.selenium.title != self._page_title: + for handle in self.selenium.window_handles: + self.selenium.switch_to_window(handle) + WebDriverWait(self.selenium, self.timeout).until(lambda s: s.title) + if self.selenium.title == self._page_title: + break + else: + raise Exception('Popup has not loaded') + + if expect == 'new': + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._email_locator).is_displayed()) + elif expect == 'returning': + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._sign_in_returning_user_locator).is_displayed()) + import time + time.sleep(2) # TODO: Remove this sleep + else: + raise Exception('Unknown expect value: %s' % expect) + + def close_window(self): + self.selenium.close() + + @property + def signed_in_email(self): + """Get the value of the email that is currently signed in.""" + return self.selenium.find_element(*self._signed_in_email_locator).text + + def click_this_is_not_me(self): + """Clicks the 'This is not me' button.""" + self.selenium.find_element(*self._this_is_not_me_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element(*self._email_locator).is_displayed()) + + @property + def emails(self): + """Get the emails for the returning user.""" + return [element.text for element in + self.selenium.find_elements(*self._emails_locator)] + + @property + def email(self): + """Get the value of the email field.""" + return self.selenium.find_element(*self._email_locator).text + + @email.setter + def email(self, value): + """Set the value of the email field.""" + email = self.selenium.find_element(*self._email_locator) + email.clear() + email.send_keys(value) + + @property + def new_email(self): + """Get the value of the new email field.""" + return self.selenium.find_element(*self._new_email_locator).text + + @new_email.setter + def new_email(self, value): + """Set the value of the new email field.""" + email = self.selenium.find_element(*self._new_email_locator) + email.clear() + email.send_keys(value) + + @property + def selected_email(self): + """Return the value of the selected email of returning user's multiple emails""" + for email in self.selenium.find_elements(*self._emails_locator): + if email.find_element(By.TAG_NAME, 'input').is_selected(): + return email.text + + def select_email(self, value): + """Select email from the returning user's multiple emails.""" + for email in self.selenium.find_elements(*self._emails_locator): + if email.text == value: + email.click() + break + else: + raise Exception('Email not found: %s' % value) + + @property + def password(self): + """Get the value of the password field.""" + return self.selenium.find_element(*self._password_locator).text + + @password.setter + def password(self, value): + """Set the value of the password field.""" + password = self.selenium.find_element(*self._password_locator) + password.clear() + password.send_keys(value) + + @property + def verify_password(self): + """Get the value of the verify password field.""" + return self.selenium.find_element(*self._verify_password_locator).text + + @verify_password.setter + def verify_password(self, value): + """Set the value of the verify password field.""" + password = self.selenium.find_element(*self._verify_password_locator) + password.clear() + password.send_keys(value) + + @property + def check_email_at_address(self): + """Get the value of the email address for confirmation.""" + return self.selenium.find_element(*self._check_email_at_locator).text + + def click_next(self, expect='password'): + """Clicks the 'next' button.""" + self.selenium.find_element(*self._next_locator).click() + if expect == 'password': + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._password_locator).is_displayed()) + elif expect == 'verify': + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._verify_email_locator).is_displayed()) + else: + raise Exception('Unknown expect value: %s' % expect) + + def click_sign_in(self): + """Clicks the 'sign in' button.""" + self.selenium.find_element(*self._sign_in_locator).click() + self.switch_to_main_window() + + def click_sign_in_returning_user(self): + """Clicks the 'sign in' button.""" + self.selenium.find_element( + *self._sign_in_returning_user_locator).click() + self.switch_to_main_window() + + def click_verify_email(self): + """Clicks 'verify email' button.""" + self.selenium.find_element(*self._verify_email_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._check_email_at_locator).is_displayed()) + + def click_forgot_password(self): + """Clicks 'forgot password' link (visible after entering a valid email)""" + self.selenium.find_element(*self._forgot_password_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._reset_password_locator).is_displayed()) + + def click_reset_password(self): + """Clicks 'reset password' after forgot password and new passwords entered""" + self.selenium.find_element(*self._reset_password_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._check_email_at_locator).is_displayed()) + + def click_add_another_email_address(self): + """Clicks 'add another email' button.""" + self.selenium.find_element(*self._add_another_email_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._add_new_email_locator).is_displayed()) + + def click_add_new_email(self): + """Clicks 'Add' button to insert new email address.""" + self.selenium.find_element(*self._add_new_email_locator).click() + WebDriverWait(self.selenium, self.timeout).until( + lambda s: s.find_element( + *self._check_email_at_locator).is_displayed()) + + def sign_in(self, email, password): + """Signs in using the specified email address and password.""" + self.email = email + self.click_next(expect='password') + self.password = password + self.click_sign_in() + + def sign_in_new_user(self, email, password): + """Requests verification email using the specified email address.""" + self.email = email + self.click_next(expect='verify') + self.password = password + self.verify_password = password + self.click_verify_email() + self.close_window() + self.switch_to_main_window() + + def sign_in_returning_user(self): + """Signs in with the stored user.""" + self.click_sign_in_returning_user() diff --git a/automation-tests/browserid/requirements.txt b/automation-tests/browserid/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..94fd2ed89d1ebf52c93c3bb428e02bb6c1d98812 --- /dev/null +++ b/automation-tests/browserid/requirements.txt @@ -0,0 +1,2 @@ +pytest-mozwebqa==1.0 +requests==0.13.3 diff --git a/automation-tests/browserid/setup.cfg b/automation-tests/browserid/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..5ca77d16be0357283249ae1e9f1456a748bccee1 --- /dev/null +++ b/automation-tests/browserid/setup.cfg @@ -0,0 +1,2 @@ +[pytest] +python_files=check_*.py diff --git a/automation-tests/browserid/tests/__init__.py b/automation-tests/browserid/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/automation-tests/browserid/tests/base.py b/automation-tests/browserid/tests/base.py new file mode 100644 index 0000000000000000000000000000000000000000..8adf6357ce14e817412fbad8532374c0df8309fa --- /dev/null +++ b/automation-tests/browserid/tests/base.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import re + +import requests +from selenium.webdriver.support.ui import WebDriverWait + +from .. import BrowserID +from .. mocks.user import MockUser +import restmail + + +class BaseTest(object): + + def browserid_url(self, base_url): + response = requests.get('%s/' % base_url, verify=False) + match = re.search(BrowserID.INCLUDE_URL_REGEX, response.content) + if match: + return match.group(1) + else: + raise Exception('Unable to determine BrowserID URL from %s.' % base_url) + + def log_out(self, selenium, timeout): + WebDriverWait(selenium, timeout).until( + lambda s: s.find_element_by_id('loggedin').is_displayed()) + selenium.find_element_by_css_selector('#loggedin a').click() + WebDriverWait(selenium, timeout).until( + lambda s: s.find_element_by_css_selector('#loggedout button').is_displayed()) + + def create_verified_user(self, selenium, timeout): + user = MockUser() + from .. pages.sign_in import SignIn + signin = SignIn(selenium, timeout, expect='new') + signin.sign_in_new_user(user.primary_email, user.password) + mail = restmail.get_mail(user.primary_email, timeout=timeout) + verify_url = re.search(BrowserID.VERIFY_URL_REGEX, + mail[0]['text']).group(0) + + selenium.get(verify_url) + from .. pages.complete_registration import CompleteRegistration + complete_registration = CompleteRegistration(selenium, + timeout, + expect='success') + assert 'Thank you' in complete_registration.thank_you + return user diff --git a/automation-tests/browserid/tests/check_add_email.py b/automation-tests/browserid/tests/check_add_email.py new file mode 100644 index 0000000000000000000000000000000000000000..79e1e00f9be379298ef5a7654125f8a9736c8a92 --- /dev/null +++ b/automation-tests/browserid/tests/check_add_email.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import re + +import pytest + +from .. import BrowserID +from base import BaseTest +import restmail + + +@pytest.mark.nondestructive +class TestSignIn(BaseTest): + + @pytest.mark.travis + def test_add_email(self, mozwebqa): + user = self.create_verified_user(mozwebqa.selenium, mozwebqa.timeout) + user.additional_emails.append('%s_1@restmail.net' % user.id) + + mozwebqa.selenium.get('%s/' % mozwebqa.base_url) + self.log_out(mozwebqa.selenium, mozwebqa.timeout) + mozwebqa.selenium.find_element_by_css_selector('#loggedout button').click() + + from .. pages.sign_in import SignIn + signin = SignIn(mozwebqa.selenium, mozwebqa.timeout, expect='returning') + signin.click_add_another_email_address() + signin.new_email = user.additional_emails[0] + signin.click_add_new_email() + signin.close_window() + signin.switch_to_main_window() + + mail = restmail.get_mail(user.additional_emails[0], + timeout=mozwebqa.timeout) + assert 'Click to confirm this email address' in mail[0]['text'] + confirm_url = re.search(BrowserID.CONFIRM_URL_REGEX, + mail[0]['text']).group(0) + + mozwebqa.selenium.get(confirm_url) + from .. pages.complete_registration import CompleteRegistration + complete_registration = CompleteRegistration(mozwebqa.selenium, + mozwebqa.timeout, + expect='success') + assert 'Your address has been verified' in complete_registration.thank_you + + mozwebqa.selenium.get('%s/' % mozwebqa.base_url) + self.log_out(mozwebqa.selenium, mozwebqa.timeout) + mozwebqa.selenium.find_element_by_css_selector('#loggedout button').click() + + signin = SignIn(mozwebqa.selenium, mozwebqa.timeout, expect='returning') + assert user.additional_emails[0] in signin.emails + assert signin.selected_email == user.additional_emails[0] diff --git a/automation-tests/browserid/tests/check_change_password.py b/automation-tests/browserid/tests/check_change_password.py new file mode 100644 index 0000000000000000000000000000000000000000..cb9e0501ae30a8c8b2b509e0b65c78caa649e586 --- /dev/null +++ b/automation-tests/browserid/tests/check_change_password.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import pytest +from selenium.webdriver.support.ui import WebDriverWait + +from .. import BrowserID +from base import BaseTest + + +@pytest.mark.nondestructive +class TestSignIn(BaseTest): + + @pytest.mark.travis + def test_change_password(self, mozwebqa): + user = self.create_verified_user(mozwebqa.selenium, mozwebqa.timeout) + + mozwebqa.selenium.get(self.browserid_url(mozwebqa.base_url)) + from .. pages.account_manager import AccountManager + account_manager = AccountManager(mozwebqa.selenium, mozwebqa.timeout) + + assert user.primary_email in account_manager.emails + + account_manager.click_edit_password() + account_manager.old_password = user.password + user.password += '_new' + account_manager.new_password = user.password + account_manager.click_password_done() + account_manager.click_sign_out() + + mozwebqa.selenium.get('%s/' % mozwebqa.base_url) + + login_locator = '#loggedout button' + WebDriverWait(mozwebqa.selenium, mozwebqa.timeout).until( + lambda s: s.find_element_by_css_selector(login_locator).is_displayed()) + mozwebqa.selenium.find_element_by_css_selector(login_locator).click() + + browser_id = BrowserID(mozwebqa.selenium, mozwebqa.timeout) + browser_id.sign_in(user.primary_email, user.password) + + WebDriverWait(mozwebqa.selenium, mozwebqa.timeout).until( + lambda s: s.find_element_by_id('loggedin').is_displayed()) diff --git a/automation-tests/browserid/tests/check_reset_password.py b/automation-tests/browserid/tests/check_reset_password.py new file mode 100644 index 0000000000000000000000000000000000000000..6dced83572eded7d8ac17a8b7cdd173f22cd9f8e --- /dev/null +++ b/automation-tests/browserid/tests/check_reset_password.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import re + +import pytest + +from .. import BrowserID +from base import BaseTest +import restmail + + +@pytest.mark.nondestructive +class TestSignIn(BaseTest): + + @pytest.mark.travis + def test_reset_password(self, mozwebqa): + user = self.create_verified_user(mozwebqa.selenium, mozwebqa.timeout) + mozwebqa.selenium.get('%s/' % mozwebqa.base_url) + self.log_out(mozwebqa.selenium, mozwebqa.timeout) + mozwebqa.selenium.find_element_by_css_selector('#loggedout button').click() + + from .. pages.sign_in import SignIn + signin = SignIn(mozwebqa.selenium, mozwebqa.timeout, expect='returning') + signin.click_this_is_not_me() + signin.email = user.primary_email + signin.click_next() + signin.click_forgot_password() + user.password += '_new' + signin.password = user.password + signin.verify_password = user.password + signin.click_reset_password() + assert signin.check_email_at_address == user.primary_email + + signin.close_window() + signin.switch_to_main_window() + mail = restmail.get_mail(user.primary_email, + message_count=2, + timeout=mozwebqa.timeout) + assert 'Click to reset your password' in mail[1]['text'] + + reset_url = re.search(BrowserID.RESET_URL_REGEX, + mail[1]['text']).group(0) + mozwebqa.selenium.get(reset_url) + + from .. pages.complete_registration import CompleteRegistration + complete_registration = CompleteRegistration(mozwebqa.selenium, + mozwebqa.timeout, + expect='success') + assert 'Your address has been verified!' in complete_registration.thank_you diff --git a/automation-tests/browserid/tests/check_sign_in.py b/automation-tests/browserid/tests/check_sign_in.py new file mode 100644 index 0000000000000000000000000000000000000000..81a5ab4765fa28c215c23e07a473a9cfe90832cd --- /dev/null +++ b/automation-tests/browserid/tests/check_sign_in.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import pytest +from selenium.webdriver.support.ui import WebDriverWait + +from .. import BrowserID +from .. mocks.user import MockUser +from base import BaseTest +import restmail + + +@pytest.mark.nondestructive +class TestSignIn(BaseTest): + + def test_sign_in_helper(self, mozwebqa): + browser_id = BrowserID(mozwebqa.selenium, mozwebqa.timeout) + browser_id.sign_in(mozwebqa.email, mozwebqa.password) + + WebDriverWait(mozwebqa.selenium, mozwebqa.timeout).until( + lambda s: s.find_element_by_id('loggedin').is_displayed()) + + def test_sign_in(self, mozwebqa): + from .. pages.sign_in import SignIn + signin = SignIn(mozwebqa.selenium, mozwebqa.timeout, expect='new') + signin.email = mozwebqa.email + signin.click_next(expect='password') + signin.password = mozwebqa.password + signin.click_sign_in() + + WebDriverWait(mozwebqa.selenium, mozwebqa.timeout).until( + lambda s: s.find_element_by_id('loggedin').is_displayed()) + + @pytest.mark.travis + def test_sign_in_new_user_helper(self, mozwebqa): + user = MockUser() + from .. pages.sign_in import SignIn + signin = SignIn(mozwebqa.selenium, mozwebqa.timeout, expect='new') + print 'signing in as %s' % user.primary_email + signin.sign_in_new_user(user.primary_email, 'password') + mail = restmail.get_mail(user.primary_email, timeout=mozwebqa.timeout) + assert 'Click to confirm this email address' in mail[0]['text'] + + @pytest.mark.travis + def test_sign_in_new_user(self, mozwebqa): + user = MockUser() + from .. pages.sign_in import SignIn + signin = SignIn(mozwebqa.selenium, mozwebqa.timeout, expect='new') + print 'signing in as %s' % user.primary_email + signin.email = user.primary_email + signin.click_next(expect='verify') + signin.password = user.password + signin.verify_password = user.password + signin.click_verify_email() + assert signin.check_email_at_address == user.primary_email + + signin.close_window() + signin.switch_to_main_window() + mail = restmail.get_mail(user.primary_email, timeout=mozwebqa.timeout) + assert 'Click to confirm this email address' in mail[0]['text'] + + @pytest.mark.travis + def test_sign_in_returning_user(self, mozwebqa): + self.create_verified_user(mozwebqa.selenium, mozwebqa.timeout) + mozwebqa.selenium.get('%s/' % mozwebqa.base_url) + WebDriverWait(mozwebqa.selenium, mozwebqa.timeout).until( + lambda s: s.find_element_by_id('loggedin').is_displayed()) diff --git a/automation-tests/browserid/tests/conftest.py b/automation-tests/browserid/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..172c531145870ee29862ddc22e3c33bcb00d3716 --- /dev/null +++ b/automation-tests/browserid/tests/conftest.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from selenium.webdriver.support.ui import WebDriverWait + + +def pytest_runtest_setup(item): + item.config.option.api = 'webdriver' + + +def pytest_funcarg__mozwebqa(request): + mozwebqa = request.getfuncargvalue('mozwebqa') + mozwebqa.selenium.get('%s/' % mozwebqa.base_url) + WebDriverWait(mozwebqa.selenium, mozwebqa.timeout).until( + lambda s: s.find_element_by_css_selector('#loggedout button').is_displayed()) + mozwebqa.selenium.find_element_by_css_selector('#loggedout button').click() + return mozwebqa diff --git a/automation-tests/browserid/tests/restmail.py b/automation-tests/browserid/tests/restmail.py new file mode 100644 index 0000000000000000000000000000000000000000..910b549fcdf2a0118c8c1eefbf2798eb91b7f72d --- /dev/null +++ b/automation-tests/browserid/tests/restmail.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import time + +import requests + + +def get_mail(username, message_count=1, timeout=60): + username = username.partition('@restmail.net')[0] + end_time = time.time() + timeout + while(True): + response = requests.get( + 'https://restmail.net/mail/%s' % username, + verify=False) + restmail = json.loads(response.content) + if len(restmail) == message_count: + return restmail + time.sleep(0.5) + if(time.time() > end_time): + break + raise Exception('Timeout after %(TIMEOUT)s seconds getting restmail for ' + '%(USERNAME)s. Expected %(EXPECTED_MESSAGE_COUNT)s ' + 'messages but there were %(ACTUAL_MESSAGE_COUNT)s.' % { + 'TIMEOUT': timeout, + 'USERNAME': username, + 'EXPECTED_MESSAGE_COUNT': message_count, + 'ACTUAL_MESSAGE_COUNT': len(restmail)})