123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782 |
- # Copyright 2013 The Distro Tracker Developers
- # See the COPYRIGHT file at the top-level directory of this distribution and
- # at http://deb.li/DTAuthors
- #
- # This file is part of Distro Tracker. It is subject to the license terms
- # in the LICENSE file found in the top-level directory of this
- # distribution and at http://deb.li/DTLicense. No part of Distro Tracker,
- # including this file, may be copied, modified, propagated, or distributed
- # except according to the terms contained in the LICENSE file.
- """
- Functional tests for Distro Tracker.
- """
- from __future__ import unicode_literals
- from distro_tracker.test import LiveServerTestCase
- from django.core.urlresolvers import reverse
- from django.contrib.auth import get_user_model
- from django.core import mail
- from django_email_accounts.models import UserEmail
- from distro_tracker.core.models import SourcePackageName, BinaryPackageName
- from distro_tracker.accounts.models import UserRegistrationConfirmation
- from distro_tracker.accounts.models import ResetPasswordConfirmation
- from distro_tracker.accounts.models import AddEmailConfirmation
- from distro_tracker.accounts.models import MergeAccountConfirmation
- from distro_tracker.core.models import ContributorName
- from distro_tracker.core.models import Team
- from distro_tracker.core.models import SourcePackage
- from distro_tracker.core.models import PackageName
- from distro_tracker.core.models import Subscription
- from distro_tracker.core.models import TeamMembership
- from distro_tracker.core.panels import BasePanel
- from selenium import webdriver
- from selenium.common.exceptions import NoSuchElementException
- import selenium.webdriver.support.ui as ui
- from selenium.webdriver.common.keys import Keys
- from django.utils.six.moves import mock
- import os
- import time
- class SeleniumTestCase(LiveServerTestCase):
- """
- A class which includes some common functionality for all tests which use
- Selenium.
- """
- def setUp(self):
- os.environ['NO_PROXY'] = 'localhost,127.0.0.1,127.0.1.1'
- fp = webdriver.FirefoxProfile()
- fp.set_preference('network.proxy.type', 0)
- self.browser = webdriver.Firefox(firefox_profile=fp)
- self.browser.implicitly_wait(3)
- self.browser.set_page_load_timeout(3)
- self.browser.set_script_timeout(3)
- def tearDown(self):
- self.browser.close()
- def get_page(self, relative):
- """
- Helper method which points the browser to the absolute URL based on the
- given relative URL and the server's live_server_url.
- """
- self.browser.get(self.absolute_url(relative))
- def wait_response(self, seconds):
- time.sleep(seconds)
- def absolute_url(self, relative):
- """
- Helper method which builds an absolute URL where the live_server_url is
- the root.
- """
- return self.live_server_url + relative
- def input_to_element(self, id, text):
- """
- Helper method which sends the text to the element with the given ID.
- """
- element = self.browser.find_element_by_id(id)
- element.send_keys(text)
- def clear_element_text(self, id):
- """
- Helper method which removes any text already found in the element with
- the given ID.
- """
- element = self.browser.find_element_by_id(id)
- element.clear()
- def click_link(self, link_text):
- """
- Helper method which clicks on the link with the given text.
- """
- element = self.browser.find_element_by_link_text(link_text)
- element.click()
- def send_enter(self, id):
- """
- Helper method which sends the enter key to the element with the given
- ID.
- """
- element = self.browser.find_element_by_id(id)
- element.send_keys(Keys.ENTER)
- def assert_in_page_body(self, text):
- body = self.browser.find_element_by_tag_name('body')
- self.assertIn(text, body.text)
- def assert_not_in_page_body(self, text):
- body = self.browser.find_element_by_tag_name('body')
- self.assertNotIn(text, body.text)
- def assert_element_with_id_in_page(self, element_id, custom_message=None):
- """
- Helper method which asserts that the element with the given ID can be
- found in the current browser page.
- """
- if custom_message is None:
- custom_message = element_id + " not found in the page."
- try:
- self.browser.find_element_by_id(element_id)
- except NoSuchElementException:
- self.fail(custom_message)
- def assert_element_with_class_in_page(self, class_name,
- custom_message=None):
- if custom_message is None:
- custom_message = class_name + " not found in the page."
- try:
- self.browser.find_element_by_class_name(class_name)
- except NoSuchElementException:
- self.fail(custom_message)
- def get_element_by_id(self, element_id):
- try:
- return self.browser.find_element_by_id(element_id)
- except NoSuchElementException:
- return None
- def get_element_by_class(self, class_name):
- try:
- return self.browser.find_element_by_class_name(class_name)
- except NoSuchElementException:
- return None
- def assert_current_url_equal(self, url):
- """
- Helper method which asserts that the given URL equals the current
- browser URL.
- The given URL should not include the domain.
- """
- self.assertEqual(
- self.browser.current_url,
- self.absolute_url(url))
- def set_mock_http_response(self, mock_requests, text, status_code=200):
- mock_response = mock_requests.models.Response()
- mock_response.status_code = status_code
- mock_response.text = text
- mock_requests.get.return_value = mock_response
- mock_requests.head.return_value = mock_response
- def create_test_panel(panel_position):
- """
- Helper test decorator which creates a TestPanel before running the test and
- unregisters it when it completes, making sure all tests are ran in
- isolation.
- """
- def decorator(func):
- def wrap(self):
- class TestPanel(BasePanel):
- html_output = "Hello, world"
- position = panel_position
- try:
- ret = func(self)
- finally:
- TestPanel.unregister_plugin()
- return ret
- return wrap
- return decorator
- class PackagePageTest(SeleniumTestCase):
- def setUp(self):
- super(PackagePageTest, self).setUp()
- self.package = SourcePackageName.objects.create(name='dummy-package')
- SourcePackageName.objects.create(name='second-package')
- self.binary_package = BinaryPackageName.objects.create(
- name='binary-package')
- self.binary_package.sourcepackage_set.create(
- source_package_name=self.package,
- version='1.0.0')
- def get_package_url(self, package_name):
- """
- Helper method returning the URL of the package with the given name.
- """
- return reverse('dtracker-package-page', kwargs={
- 'package_name': package_name,
- })
- def send_text_to_package_search_form(self, text):
- """
- Helper function to send text input to the package search form.
- """
- search_form = self.browser.find_element_by_id('package-search-form')
- text_box = search_form.find_element_by_name('package_name')
- # Make sure any old text is removed.
- text_box.clear()
- text_box.send_keys(text)
- text_box.send_keys(Keys.ENTER)
- def test_access_source_package_page_by_url(self):
- """
- Tests that users can get to a package's page by going straight to its
- URL.
- """
- # The user tries to visit a package's page.
- self.get_page(self.get_package_url(self.package.name))
- # The browser shows the package's page, indicated in the page
- # title.
- self.assertIn(self.package.name, self.browser.title)
- # It is displayed in the content, as well.
- package_name_element = self.browser.find_element_by_tag_name('h1')
- self.assertEqual(package_name_element.text, self.package.name)
- # The user sees a footer with general information
- self.assert_element_with_id_in_page('footer')
- # There is a header with a form with a text box where the user can
- # type in the name of a package to get to its page.
- self.assert_element_with_id_in_page('package-search-form',
- "Form not found")
- # So, the uer types the name of another source package...
- self.send_text_to_package_search_form('second-package')
- # This causes the new pacakge's page to open.
- self.assertEqual(
- self.browser.current_url,
- self.absolute_url(self.get_package_url('second-package')))
- # The user would like to see the source package page for a binary
- # package. The user types the package name in the search form.
- self.send_text_to_package_search_form('binary-package')
- self.assertEqual(
- self.browser.current_url,
- self.absolute_url(self.get_package_url(self.package.name)))
- # However, when the user tries a package name which does not exist,
- # they expects the response page to state this.
- self.send_text_to_package_search_form('no-exist')
- self.assert_in_page_body('Package no-exist does not exist')
- def test_access_package_page_from_index(self):
- """
- Tests that the user can access a package page starting from the index
- and using the provided form.
- """
- # The user opens the start page
- self.get_page('/')
- # The page title should show the index page of the site.
- self.assertIn('Package Tracker', self.browser.title)
- # There is a form to use for access to packages.
- self.assert_element_with_id_in_page('package-search-form')
- # The user types in a name of a known source package...
- self.send_text_to_package_search_form(self.package.name)
- # ...and expects the response to show the package page.
- self.assertEqual(
- self.browser.current_url,
- self.absolute_url(self.package.get_absolute_url()))
- # The user goes back to the index...
- self.browser.back()
- # ...and tries using the form to access a package page, but the package
- # does not exist.
- self.send_text_to_package_search_form('no-exist')
- self.assert_in_page_body('Package no-exist does not exist')
- @create_test_panel('left')
- def test_include_panel_left(self):
- """
- Tests whether a package page includes a panel in the left side column.
- """
- self.get_page(self.get_package_url(self.package.name))
- self.assert_element_with_id_in_page('dtracker-package-left')
- column = self.browser.find_element_by_id('dtracker-package-left')
- self.assertIn("Hello, world", column.text)
- @create_test_panel('center')
- def test_include_panel_center(self):
- """
- Tests whether a package page includes a panel in the center column.
- """
- self.get_page(self.get_package_url(self.package.name))
- self.assert_element_with_id_in_page('dtracker-package-center')
- column = self.browser.find_element_by_id('dtracker-package-center')
- self.assertIn("Hello, world", column.text)
- @create_test_panel('right')
- def test_include_panel_right(self):
- """
- Tests whether a package page includes a panel in the right side column.
- """
- self.get_page(self.get_package_url(self.package.name))
- self.assert_element_with_id_in_page('dtracker-package-right')
- column = self.browser.find_element_by_id('dtracker-package-right')
- self.assertIn("Hello, world", column.text)
- User = get_user_model()
- class RepositoryAdminTest(SeleniumTestCase):
- def setUp(self):
- super(RepositoryAdminTest, self).setUp()
- # Create a superuser which will be used for the tests
- User.objects.create_superuser(
- main_email='admin',
- password='admin'
- )
- def login_to_admin(self, username='admin', password='admin'):
- """
- Helper method which logs the user with the given credentials to the
- admin console.
- """
- self.get_page('/admin/')
- self.input_to_element('id_username', username)
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- @mock.patch('distro_tracker.core.admin.requests')
- @mock.patch('distro_tracker.core.retrieve_data.requests')
- def test_repository_add(self, mock_requests, mock_requests2):
- """
- Tests that an admin user is able to add a new repository.
- """
- # The user first logs in to the admin panel with their credentials.
- self.login_to_admin()
- # They expect the log in to succeed, responsing with the
- # administration page.
- self.assertIn('Site administration', self.browser.title)
- # The user now wants to go to the repositories management
- # page. The necessary link can be found in the page.
- try:
- self.browser.find_element_by_link_text("Repositories")
- except NoSuchElementException:
- self.fail("Link for repositories management not found in the admin")
- # Clicking on it opens a new page to manage repositories.
- self.click_link("Repositories")
- self.assertIn(
- 'Repositories',
- self.browser.find_element_by_class_name('breadcrumbs').text
- )
- # The user now wants to create a new repository.
- self.click_link("Add repository")
- self.assert_in_page_body("Add repository")
- try:
- save_button = self.browser.find_element_by_css_selector(
- 'input.default')
- except NoSuchElementException:
- self.fail("Could not find the save button")
- # The user tries clicking the save button immediately
- save_button.click()
- # But this causes an error since there are some required fields.
- self.assert_in_page_body('Please correct the errors below')
- # The user enters a name and shorthand for the repository.
- self.input_to_element('id_name', 'stable')
- self.input_to_element('id_shorthand', 'stable')
- # They want to create the repository by using a sources.list entry.
- self.input_to_element(
- 'id_sources_list_entry',
- 'deb http://ftp.bad.debian.org/debian stable'
- )
- # === Make sure that no actual HTTP requests are sent out ===
- self.set_mock_http_response(
- mock_requests,
- 'Suite: stable\n'
- 'Codename: wheezy\n'
- 'Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64'
- ' kfreebsd-i386 mips mipsel powerpc s390 s390x sparc\n'
- 'Components: main contrib non-free\n'
- 'Version: 7.1\n'
- 'Description: Debian 7.1 Released 15 June 2013\n'
- )
- self.set_mock_http_response(mock_requests2, 'OK')
- # The user decides to save by hitting the enter key
- self.send_enter('id_sources_list_entry')
- # The response page shows confirmation the repository has been added.
- self.assert_in_page_body("added successfully")
- # The page also shows the information of the newly added repository.
- self.assert_in_page_body('Codename')
- self.assert_in_page_body('wheezy')
- self.assert_in_page_body('Components')
- self.assert_in_page_body('main contrib non-free')
- # The user now wants to add another repository
- self.click_link("Add repository")
- # This time, they want to enter all the necessary data manually.
- self.input_to_element('id_name', 'testing')
- self.input_to_element('id_shorthand', 'testing')
- self.input_to_element('id_uri', 'http://ftp.bad.debian.org/debian')
- self.input_to_element('id_suite', 'testing')
- self.input_to_element('id_codename', 'jessie')
- self.input_to_element('id_components', 'main non-free')
- architecture_option = self.browser.find_element_by_css_selector(
- '.field-architectures select option[value="1"]')
- architecture_option.click()
- # Finally the user clicks the save button
- self.browser.find_element_by_css_selector('input.default').click()
- # The response page confirms that the new repository has been created.
- self.assert_in_page_body("added successfully")
- # The page also shows the information of the newly added repository.
- self.assert_in_page_body('jessie')
- self.assert_in_page_body('main non-free')
- class UserAccountsTestMixin(object):
- """
- Defines some common methods for all user account tests.
- """
- def setUp(self):
- super(UserAccountsTestMixin, self).setUp()
- self.package = SourcePackageName.objects.create(name='dummy-package')
- self.password = 'asdf'
- self.user = User.objects.create_user(
- main_email='user@domain.com', password=self.password,
- first_name='', last_name='')
- def refresh_user_object(self):
- """
- The method retrieves the user instance from the database forcing any
- cached properties to reload. This can be used when the user's
- properties need to be tested for updated values.
- """
- self.user = User.objects.get(main_email=self.user.main_email)
- def get_login_url(self):
- return reverse('dtracker-accounts-login')
- def get_profile_url(self):
- return reverse('dtracker-accounts-profile')
- def get_package_url(self, package_name):
- return reverse('dtracker-package-page', kwargs={
- 'package_name': package_name,
- })
- def create_user(self, main_email, password, associated_emails=()):
- u = User.objects.create_user(main_email, password=password)
- for associated_email in associated_emails:
- u.emails.create(email=associated_email)
- return u
- def log_in(self, user=None, password=None):
- """
- Helper method which logs the user in, without taking any shortcuts (it
- goes through the steps to fill in the form and submit it).
- """
- if user is None:
- user = self.user
- if password is None:
- password = self.password
- self.get_page(self.get_login_url())
- self.input_to_element('id_username', user.main_email)
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- class UserRegistrationTest(UserAccountsTestMixin, SeleniumTestCase):
- """
- Tests for the user registration story.
- """
- def setUp(self):
- super(UserRegistrationTest, self).setUp()
- # User registration tests do not want any already registered users
- UserEmail.objects.all().delete()
- User.objects.all().delete()
- def get_confirmation_url(self, message):
- """
- Extracts the confirmation URL from the given email message.
- Returns ``None`` if the message did not contain a confirmation URL.
- """
- match = self.re_confirmation_url.search(message.body)
- if not match:
- return None
- return match.group(1)
- def get_registration_url(self):
- return reverse('dtracker-accounts-register')
- def test_user_register(self):
- profile_url = self.get_profile_url()
- password_form_id = 'form-reset-password'
- user_email = 'user@domain.com'
- # === Preconditions: ===
- # === No registered users or command confirmations ===
- self.assertEqual(0, User.objects.count())
- self.assertEqual(0, UserRegistrationConfirmation.objects.count())
- # === Start of the test. ===
- # The user opens the front page
- self.get_page('/')
- # The page shows a link to a registration page
- try:
- self.browser.find_element_by_link_text("Register")
- except NoSuchElementException:
- self.fail("Link for user registration not found on the front page")
- # Upon clicking the link, the user is taken to the registration page
- self.click_link("Register")
- self.assert_current_url_equal(self.get_registration_url())
- # The page shows a registration form
- self.assert_element_with_id_in_page('form-register')
- # The user inputs only the email address
- self.input_to_element("id_main_email", user_email)
- self.send_enter('id_main_email')
- # The user is notified of a successful registration
- self.assert_current_url_equal(
- reverse('dtracker-accounts-register-success'))
- # The user receives an email with the confirmation URL
- self.assertEqual(1, len(mail.outbox))
- # === Get confirmation key from the database ===
- self.assertEqual(1, UserRegistrationConfirmation.objects.count())
- confirmation = UserRegistrationConfirmation.objects.all()[0]
- self.assertIn(confirmation.confirmation_key, mail.outbox[0].body)
- # The user goes to the confirmation URL
- confirmation_url = reverse(
- 'dtracker-accounts-confirm-registration', kwargs={
- 'confirmation_key': confirmation.confirmation_key
- })
- self.get_page(confirmation_url)
- # The response page shows a password entry form.
- self.assert_element_with_id_in_page(password_form_id)
- # However, the user first goes back to the index...
- self.get_page('/')
- # ...and then goes back to the confirmation page which is still valid
- self.get_page(confirmation_url)
- password = 'asdf'
- self.input_to_element('id_password1', password)
- self.input_to_element('id_password2', password)
- self.send_enter('id_password2')
- # The user is now successfully logged in with their profile page open.
- self.assert_current_url_equal(profile_url)
- # A message confirms that the user is now registered.
- self.assert_in_page_body('You have successfully registered to the')
- # When the user tries opening the confirmation page for the same key
- # again, it is no longer valid
- self.get_page(confirmation_url)
- with self.assertRaises(NoSuchElementException):
- self.browser.find_element_by_id(password_form_id)
- # This is because the confirmation model instance has been removed...
- self.assertEqual(0, UserRegistrationConfirmation.objects.count())
- # The user goes back to the profile page and this time there is no
- # message confirming their registration.
- self.get_page(profile_url)
- self.assert_not_in_page_body('You have successfully registered to the')
- # The user now wishes to log out
- self.assert_in_page_body('Log out')
- self.click_link('Log out')
- # Because the session was on a private page, the user is now
- # redirected back to the index page.
- self.assert_current_url_equal('/')
- # From there, the user tries logging in with their new account.
- self.click_link('Log in')
- self.input_to_element('id_username', user_email)
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- # The response is the user's profile page.
- self.assert_current_url_equal(self.get_profile_url())
- def test_register_email_already_has_subscriptions(self):
- """
- Tests that a user can register using an email which already has
- subscriptions to some packages.
- """
- # === Set up such an email ===
- email = UserEmail.objects.create(email='user@domain.com')
- package_name = 'dummy-package'
- Subscription.objects.create_for(
- email=email,
- package_name=package_name)
- # The user opens the registration page and enters the email
- self.get_page(self.get_registration_url())
- self.input_to_element('id_main_email', email.email)
- self.send_enter('id_main_email')
- self.wait_response(1)
- # The user is successfully registered
- self.assertEqual(1, User.objects.count())
- user = User.objects.all()[0]
- self.assertEqual(email.email, user.main_email)
- self.assertEqual(
- [email.email],
- [e.email for e in user.emails.all()])
- # A message confirms that the user's registration is successful.
- self.assert_in_page_body(
- 'Congratulations, the registration is almost over.')
- # The existing subscriptions are not removed
- self.assertTrue(user.is_subscribed_to(package_name))
- def test_user_registered(self):
- """
- Tests that a user registration fails when there is already a registered
- user with the given email.
- """
- # === Set up a registered user ===
- user_email = 'user@domain.com'
- associated_email = 'email@domain.com'
- self.create_user(user_email, 'asdf', [associated_email])
- # The user goes to the registration page
- self.get_page(self.get_registration_url())
- # The user enters the already existing user's email
- self.input_to_element('id_main_email', user_email)
- self.send_enter('id_main_email')
- # The response is the same page...
- self.assert_current_url_equal(self.get_registration_url())
- # ... and shows an error message for the duplicate email address.
- self.assert_in_page_body('email address is already in use')
- # The user now tries using another email address associated
- # with the existing user account.
- self.clear_element_text('id_main_email')
- self.input_to_element('id_main_email', associated_email)
- self.send_enter('id_main_email')
- # The response is that same page...
- self.assert_current_url_equal(self.get_registration_url())
- # ... and shows an error message for the duplicate email address.
- self.assert_in_page_body('email address is already in use')
- def test_login(self):
- """
- Tests that a user can log in when they already have an account.
- """
- # === Set up an account ===
- user_email = 'user@domain.com'
- associated_emails = ['email@domain.com']
- password = 'asdf'
- self.create_user(user_email, password, associated_emails)
- # The user opens the front page and tries going to the log in page
- self.get_page('/')
- self.assert_in_page_body('Log in')
- self.click_link('Log in')
- # The user is now found in the log in page
- self.assert_current_url_equal(self.get_login_url())
- # The page shows a log in form.
- self.assert_element_with_id_in_page('form-login')
- # The user enters the correct email address, but incorrect password.
- self.input_to_element('id_username', user_email)
- self.input_to_element('id_password', 'fdsa')
- self.send_enter('id_password')
- # The response shows an error message for incorrect credentials.
- self.assert_in_page_body('Please enter a correct email and password')
- # Now the user correctly enters the password. The email
- # address should not need to be entered again.
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- # The user is redirected to their profile page.
- self.assert_current_url_equal(self.get_profile_url())
- def test_login_associated_email(self):
- """
- Tests that a user can log in with an associated email.
- """
- # === Set up an account ===
- user_email = 'user@domain.com'
- associated_emails = ['email@domain.com']
- password = 'asdf'
- self.create_user(user_email, password, associated_emails)
- # The user goes to the log in page
- self.get_page(self.get_login_url())
- # The page shows a log in form.
- self.assert_element_with_id_in_page('form-login')
- # The user enters the associated email address and password.
- self.input_to_element('id_username', associated_emails[0])
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- # The user is redirected to their profile page.
- self.assert_current_url_equal(self.get_profile_url())
- def test_logout_from_package_page(self):
- """
- If a user logs out when on the package page, the response
- should not redirect to the index.
- """
- # === Set up an account ===
- user_email = 'user@domain.com'
- associated_emails = ['email@domain.com']
- password = 'asdf'
- self.create_user(user_email, password, associated_emails)
- # === Set up an existing package ===
- package_name = 'dummy'
- SourcePackageName.objects.create(name=package_name)
- # The user logs in
- self.get_page(self.get_login_url())
- self.input_to_element('id_username', associated_emails[0])
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- # The user goes to the package page
- self.get_page('/' + package_name)
- # The page shows a link to log out.
- self.assert_in_page_body('Log out')
- # The user selects the link to log out.
- self.click_link('Log out')
- # The user is still at the package page, but no longer logged in
- self.assert_current_url_equal(self.get_package_url(package_name))
- self.assert_not_in_page_body('Log out')
- self.assert_in_page_body('Log in')
- # The user tries going to their profile page, but is
- # definitely logged out...
- self.get_page(self.get_profile_url())
- # ... which means the response redirects to the log in page.
- self.assert_current_url_equal(
- self.get_login_url() + '?next=' + self.get_profile_url())
- class SubscribeToPackageTest(UserAccountsTestMixin, SeleniumTestCase):
- """
- Tests for stories regarding subscribing to a package over the Web.
- """
- def get_subscriptions_url(self):
- return reverse('dtracker-accounts-subscriptions')
- def test_subscribe_from_package_page(self):
- """
- Tests that a user that has only one email address can subscribe to a
- package directly from the package page.
- """
- # The user first logs in
- self.log_in()
- # The user opens a package page
- self.get_page('/' + self.package.name)
- # The page shows a button allowing them to subscribe to the package.
- self.assert_element_with_id_in_page('subscribe-button')
- # So they click it.
- button = self.get_element_by_id('subscribe-button')
- button.click()
- # The subscribe button is no longer found in the page
- button = self.get_element_by_id('subscribe-button')
- # === Give the page a chance to refresh ===
- wait = ui.WebDriverWait(self.browser, 1)
- wait.until(lambda browser: not button.is_displayed())
- self.assertFalse(button.is_displayed())
- # It has been replaced by the unsubscribe button
- self.assert_element_with_id_in_page('unsubscribe-button')
- unsubscribe_button = self.get_element_by_id('unsubscribe-button')
- self.assertTrue(unsubscribe_button.is_displayed())
- # === The user has really been subscribed to the package? ===
- self.assertTrue(self.user.is_subscribed_to(self.package))
- def test_subscribe_not_logged_in(self):
- """
- Tests that when a user is not logged in, the response
- redirects to the log in page instead of subscribing to the
- package.
- """
- # The user opens the package page
- self.get_page('/' + self.package.name)
- # ...and tries subscribing to the package
- self.get_element_by_id('subscribe-not-logged-in-button').click()
- # ...only to find himself redirected to the log in page.
- self.assert_current_url_equal(self.get_login_url())
- def test_subscribe_multiple_associated_emails(self):
- """
- Tests that a user with multiple associated email addresses is
- offered a choice which address to use to subscribe to a
- package.
- """
- # === Set up such a user ===
- other_email = 'other-email@domain.com'
- self.user.emails.create(email=other_email)
- # The user logs in
- self.log_in()
- # The user opens a package page and clicks to subscribe button
- self.get_page('/' + self.package.name)
- self.get_element_by_id('subscribe-button').click()
- self.wait_response(1)
- # The user is presented with a choice of their email addresses.
- for email in self.user.emails.all():
- self.assert_in_page_body(email.email)
- # The user decides to cancel the subscription by dismissing the popup
- self.get_element_by_id('cancel-choose-email').click()
- self.wait_response(1)
- # === The user is not subscribed to anything yet ===
- self.assertEqual(0, Subscription.objects.count())
- # The user clicks the subscribe button again
- self.get_element_by_id('subscribe-button').click()
- self.wait_response(1)
- # ... and chooses to subscribe using their associated email address.
- self.assert_element_with_id_in_page('choose-email-1')
- self.get_element_by_id('choose-email-1').click()
- self.wait_response(1)
- # === User is now subscribed with only the clicked email ===
- self.assertEqual(1, Subscription.objects.count())
- sub = Subscription.objects.all()[0]
- self.assertEqual(other_email, sub.email_settings.user_email.email)
- # The UI that the user sees reflects this
- self.assert_element_with_id_in_page('unsubscribe-button')
- unsubscribe_button = self.get_element_by_id('unsubscribe-button')
- self.assertTrue(unsubscribe_button.is_displayed())
- def test_unsubscribe_all_emails(self):
- """
- Tests unsubscribing all user's emails from a package.
- """
- # === Set up a user with multiple emails subscribed to a package ===
- other_email = 'other-email@domain.com'
- self.user.emails.create(email=other_email)
- for email in self.user.emails.all():
- Subscription.objects.create_for(
- email=email.email,
- package_name=self.package.name)
- # The user logs in and opens the package page
- self.log_in()
- self.get_page('/' + self.package.name)
- # The page shows a button to unsubscribe from the package.
- self.assert_in_page_body('Unsubscribe')
- self.assert_element_with_id_in_page('unsubscribe-button')
- # The user decides to unsubscribe and clicks the button...
- self.get_element_by_id('unsubscribe-button').click()
- self.wait_response(1)
- # === The user is really unsubscribed from the package ===
- self.assertFalse(self.user.is_subscribed_to(self.package))
- # The user sees the subscribe button instead of the unsubscribe button
- sub_button = self.get_element_by_id('subscribe-button')
- self.assertTrue(sub_button.is_displayed())
- unsub_button = self.get_element_by_id('unsubscribe-button')
- self.assertFalse(unsub_button.is_displayed())
- def test_subscribe_package_from_subscription_tab(self):
- """
- This test validates that a user can correctly subscribe to a package
- from the subscription tab in its personnal space.
- """
- # Initially the user is not subscribed to the package
- self.assertFalse(self.user.is_subscribed_to(self.package))
- # The user logs in and goes to their subscriptions page
- self.log_in()
- self.get_page(self.get_subscriptions_url())
- # To ensure the subscription page is fully charged
- self.wait_response(1)
- self.assert_in_page_body('Subscribe')
- # Checking that at least one checkbox is checked
- available_mails = self.browser.find_elements_by_xpath(
- "//input[@type='checkbox'][@name='email']")
- is_there_checked_emails = False
- for checkbox in available_mails:
- if checkbox.is_selected():
- is_there_checked_emails = True
- break
- self.assertTrue(is_there_checked_emails)
- # Filling the package search field
- self.assert_element_with_id_in_page('package-search-input')
- self.input_to_element('package-search-input', self.package.name)
- # Subscribing to the package and ensuring it's completely done!
- self.send_enter('package-search-input')
- self.wait_response(1)
- self.assertTrue(self.user.is_subscribed_to(self.package))
- def test_package_subscription_no_email_from_subscription_tab_fails(self):
- """
- The UI should prevent the user from forgetting to check at least one
- email checkbox from the subscription tab in its personnal space.
- """
- # Initially the user is not subscribed to the package
- self.assertFalse(self.user.is_subscribed_to(self.package))
- # The user logs in and goes to their subscriptions page
- self.log_in()
- self.get_page(self.get_subscriptions_url())
- # To ensure the subscription page is fully charged
- self.wait_response(1)
- self.assert_in_page_body('Subscribe')
- # All email checkboxes should be unchecked
- available_mails = self.browser.find_elements_by_xpath(
- "//input[@type='checkbox'][@name='email']")
- for checkbox in available_mails:
- if checkbox.is_selected():
- checkbox.click()
- # The user specifies the package name...
- self.assert_element_with_id_in_page('package-search-input')
- self.input_to_element('package-search-input', self.package.name)
- # ... then submits the form to subscribe to the package.
- self.send_enter('package-search-input')
- self.wait_response(1)
- # The page shows a message stating that the field is required.
- self.assert_in_page_body('You need to select at least an email')
- # The user should still not be subscribed to the package.
- self.assertFalse(self.user.is_subscribed_to(self.package))
- def test_package_subscription_no_package_from_subscription_tab_fails(self):
- """
- The UI should prevent the user from forgetting to check at least one
- email checkbox from the subscription tab in its personnal space.
- """
- # Initially the user is not subscribed to the package
- self.assertFalse(self.user.is_subscribed_to(self.package))
- # The user logs in and goes to their subscriptions page.
- self.log_in()
- self.get_page(self.get_subscriptions_url())
- # To ensure the subscription page is fully charged
- self.wait_response(1)
- self.assert_in_page_body('Subscribe')
- # Checking that at least one checkbox is checked
- available_mails = self.browser.find_elements_by_xpath(
- "//input[@type='checkbox'][@name='email']")
- is_there_checked_emails = False
- for checkbox in available_mails:
- if checkbox.is_selected():
- is_there_checked_emails = True
- break
- self.assertTrue(is_there_checked_emails)
- # The user specifies an empty package name...
- self.assert_element_with_id_in_page('package-search-input')
- self.input_to_element('package-search-input', '')
- # ... then submits the form to subscribe to the package.
- self.send_enter('package-search-input')
- self.wait_response(1)
- # The page shows a message stating that the field is required.
- self.assert_in_page_body('This field is required')
- # The user should still not be subscribed to the package.
- self.assertFalse(self.user.is_subscribed_to(self.package))
- class ChangeProfileTest(UserAccountsTestMixin, SeleniumTestCase):
- def test_modify_personal_info(self):
- """
- Tests that the user is able to change their personal info upon
- logging in.
- """
- # The user logs in
- self.log_in()
- # The response page shows a link to modify personal information.
- self.assert_in_page_body('Personal Information')
- self.click_link('Personal Information')
- # The page shows a form to change the user's name.
- self.assert_element_with_id_in_page('form-change-profile')
- # The user decides to input a new name
- name = 'Name'
- old_last_name = self.user.last_name
- self.input_to_element('id_first_name', name)
- # ...and submits the form
- self.send_enter('id_first_name')
- # The user is met with a notification that the information has been
- # updated.
- self.assert_in_page_body('Successfully changed your information')
- # === The user's name has really changed ===
- self.refresh_user_object()
- self.assertEqual(name, self.user.first_name)
- # === But the last name has not ===
- self.assertEqual(old_last_name, self.user.last_name)
- # The user now wants to update both their first and last name.
- self.clear_element_text('id_first_name')
- new_first_name, new_last_name = 'Name', 'Last Name'
- # The user fills in the form
- self.input_to_element('id_first_name', new_first_name)
- self.input_to_element('id_last_name', new_last_name)
- # ...and submits it.
- self.send_enter('id_last_name')
- # The response shows a confirmation of success.
- self.assert_in_page_body('Successfully changed your information')
- # === The information has actually been updated ===
- self.refresh_user_object()
- self.assertEqual(new_first_name, self.user.first_name)
- self.assertEqual(new_last_name, self.user.last_name)
- # The user navigates away from the page now
- self.get_page(self.get_profile_url())
- # And then goes back
- self.click_link('Personal Information')
- # There are no notifications about modification in the page nw
- self.assert_not_in_page_body('Successfully changed your information')
- # And the user's first/last name is already filled in the form
- self.assertEqual(
- new_first_name,
- self.get_element_by_id('id_first_name').get_attribute('value'))
- self.assertEqual(
- new_last_name,
- self.get_element_by_id('id_last_name').get_attribute('value'))
- def test_change_password(self):
- """
- Tests that the user can change their password upon logging in.
- """
- # The user logs in
- self.log_in()
- # The response page shows a link to change their password...
- self.assert_in_page_body('Change Password')
- # ... and clicks it.
- self.click_link('Change Password')
- # The response page shows a form to enter the new password.
- self.assert_element_with_id_in_page('form-change-password')
- # The user first enters a wrong current password
- new_password = 'new-password'
- self.input_to_element('id_old_password', 'this-password-is-incorrect')
- self.input_to_element('id_new_password1', new_password)
- self.input_to_element('id_new_password2', new_password)
- self.send_enter('id_new_password2')
- # The response shows an error saying the current password was
- # incorrect.
- self.assert_in_page_body('Your old password was entered incorrectly')
- # The user enters their current password correctly, but
- # forgets the new password.
- self.input_to_element('id_old_password', self.password)
- self.send_enter('id_old_password')
- # The response shows a message that the field is required.
- self.assert_in_page_body('This field is required')
- # This time, the user enters both the old password and fills in the new
- # password fields, but they are mismatched
- self.input_to_element('id_old_password', self.password)
- self.input_to_element('id_new_password1', new_password)
- self.input_to_element('id_new_password2', new_password + '-miss-match')
- self.send_enter('id_new_password2')
- # The response shows a message that the password change failed
- # again.
- self.assert_in_page_body("The two password fields didn't match")
- # In the end, the user manages to fill in the form correctly!
- self.input_to_element('id_old_password', self.password)
- self.input_to_element('id_new_password1', new_password)
- self.input_to_element('id_new_password2', new_password)
- self.send_enter('id_new_password2')
- # The response shows a message confirming that the password
- # was changed.
- self.assert_in_page_body('Successfully updated your password')
- # The user logs out in order to try using their new password.
- self.click_link('Log out')
- # The user tries logging in using their old account password.
- self.log_in()
- # The response shows an error message for incorrect credentials.
- self.assert_in_page_body('Please enter a correct email and password')
- # Now they try with their new password.
- self.password = new_password
- self.log_in()
- # The user is finally logged in using their new account details.
- self.assert_current_url_equal(self.get_profile_url())
- def test_reset_password(self):
- """
- Tests that a user is able to reset their password if they forgot it.
- """
- # The user goes to the login page
- self.get_page(self.get_login_url())
- # The page shows a link to reset their password.
- self.assert_in_page_body('Forgot your password?')
- # The user has forgotten their password, so clicks the link.
- self.click_link('Forgot your password?')
- # The user sees a form to reset their password.
- self.assert_element_with_id_in_page('form-reset-password')
- # First they enter an email address not associated with any account.
- self.input_to_element('id_email', 'this-does-not-exist@domain.com')
- self.send_enter('id_email')
- # The response is the same page, with a warning that there is
- # no user with that email address.
- self.assert_in_page_body('No user with the given email is registered')
- # The user now correctly enters their own email address.
- self.clear_element_text('id_email')
- self.input_to_element('id_email', self.user.main_email)
- self.send_enter('id_email')
- # The response is another page, with a message that they must
- # check their email for a confirmation message.
- self.assert_in_page_body('Please check your email inbox for details')
- # === A confirmation email is actually sent? ===
- self.assertEqual(1, len(mail.outbox))
- confirmation = ResetPasswordConfirmation.objects.all()[0]
- # The user goes to the confirmation URL.
- self.get_page(reverse('dtracker-accounts-reset-password', kwargs={
- 'confirmation_key': confirmation.confirmation_key,
- }))
- # The response page asks them to enter a new password...
- self.assert_in_page_body('please enter a new password for your account')
- # ...so they do.
- new_password = self.password + '-new'
- self.input_to_element('id_password1', new_password)
- self.input_to_element('id_password2', new_password)
- self.send_enter('id_password2')
- # The response page redirects to the profile page, with a
- # message that their password has been reset.
- self.assert_current_url_equal(self.get_profile_url())
- self.assert_in_page_body('You have successfully reset your password')
- # The user logs out and tries logging back in with their new
- # password.
- self.click_link('Log out')
- self.password = new_password
- self.log_in()
- # The user has successfully logged in.
- self.assert_current_url_equal(self.get_profile_url())
- def test_manage_account_emails(self):
- """
- Tests that the user can manage which email addresses are
- associated with their account.
- """
- # The user logs in and goes to the account email management page
- self.log_in()
- self.click_link('Account Emails')
- # The response page shows a form to add new email addresses to
- # their account.
- self.assert_element_with_id_in_page('form-add-account-email')
- # The user adds a new email address.
- new_email = 'completely-new-email@domain.com'
- self.input_to_element('id_email', new_email)
- self.send_enter('id_email')
- # The user is notified that in order to activate the email association
- # they must demonstrate ownership of the email address.
- self.assert_in_page_body('you must follow the confirmation link')
- self.assert_not_in_page_body(new_email)
- # === The confirmation email sent? ===
- self.assertEqual(1, len(mail.outbox))
- self.assertIn(new_email, mail.outbox[0].to)
- # === Confirmation created? ===
- self.assertEqual(1, AddEmailConfirmation.objects.count())
- confirmation = AddEmailConfirmation.objects.all()[0]
- # The user now visits the confirmation URL...
- self.get_page(reverse('dtracker-accounts-confirm-add-email', kwargs={
- 'confirmation_key': confirmation.confirmation_key,
- }))
- # The response page shows a confirmation message that the
- # address is associated with their account.
- self.assert_in_page_body('now associated with your account')
- # The user goes back to their profile page.
- self.click_link('Profile')
- self.click_link('Account Emails')
- # The new email address is now in the list of email addresses
- # for the account.
- self.assert_in_page_body(new_email)
- # The user tries adding an email already associated with their account.
- self.input_to_element('id_email', new_email)
- self.send_enter('id_email')
- # The response shows a warning that the account is already
- # associated with the given email address.
- self.assert_in_page_body(
- 'This email is already associated with your account')
- def test_merge_accounts(self):
- # === Set up an additional existing user account ===
- password = 'other-password'
- other_email = 'other@domain.com'
- other_user = self.create_user(other_email, password)
- # The user logs in, then goes to the form to add an email address.
- self.log_in()
- self.click_link('Account Emails')
- # They input an address already associated with a different user.
- self.input_to_element('id_email', other_email)
- self.send_enter('id_email')
- # The response page requests confirmation to merge the accounts.
- self.assert_in_page_body('Are you sure you want to merge the accounts')
- # The user clicks the button to confirm the merge.
- self.assert_element_with_id_in_page('confirm-merge-button')
- self.get_element_by_id('confirm-merge-button').click()
- # The response notifies the user the merge is ineffective
- # until the confirmation link is visited.
- self.assert_in_page_body('you must follow a confirmation link')
- # A confirmation mail is sent
- self.assertEqual(1, len(mail.outbox))
- # The mail was not sent to the logged in user, rather the one being
- # merged to the account
- self.assertIn(other_email, mail.outbox[0].to)
- # === A confirmation instance is created? ===
- self.assertEqual(1, MergeAccountConfirmation.objects.count())
- confirmation = MergeAccountConfirmation.objects.all()[0]
- # The user tries going to the confirmation URL without logging in to
- # the other account
- confirmation_url = reverse('dtracker-accounts-merge-finalize', kwargs={
- 'confirmation_key': confirmation.confirmation_key,
- })
- self.get_page(confirmation_url)
- # ...which is forbidden and has no effect
- self.assertEqual(2, User.objects.count())
- # The user now logs in with the other account
- self.log_in(other_user, password)
- # The user visits the URL from the confirmation email message.
- self.get_page(confirmation_url)
- # The response page asks for a final confirmation.
- self.assert_in_page_body(
- 'Are you sure you want to finalize the accounts merge')
- self.assert_element_with_id_in_page('finalize-merge-button')
- # The user decides to go on with the merge
- self.get_element_by_id('finalize-merge-button').click()
- # The user is notified that the merge was successful
- self.assert_in_page_body(
- 'The two accounts have been successfully merged')
- # === User accounts are really changed? ===
- self.assertEqual(1, User.objects.count())
- # The user tries logging in with the merged account's password...
- self.log_in(password=password)
- # ...which fails.
- self.assert_in_page_body('Please enter a correct email and password')
- # They log in with the original account details...
- self.log_in()
- # ...which works.
- self.assert_current_url_equal(self.get_profile_url())
- # Both the email addresses are shown as associated with the
- # user's account.
- self.click_link('Account Emails')
- self.assert_in_page_body(self.user.main_email)
- self.assert_in_page_body(other_email)
- class TeamTests(SeleniumTestCase):
- def setUp(self):
- super(TeamTests, self).setUp()
- self.password = 'asdf'
- self.user = User.objects.create_user(
- main_email='user@domain.com', password=self.password,
- first_name='', last_name='')
- def get_login_url(self):
- return reverse('dtracker-accounts-login')
- def get_create_team_url(self):
- return reverse('dtracker-teams-create')
- def get_team_url(self, team_name):
- team = Team.objects.get(name=team_name)
- return team.get_absolute_url()
- def get_delete_team_url(self, team_name):
- team = Team.objects.get(name=team_name)
- return reverse('dtracker-team-delete', kwargs={
- 'slug': team.slug,
- })
- def get_team_deleted_url(self):
- return reverse('dtracker-team-deleted')
- def get_update_team_url(self, team_name):
- team = Team.objects.get(name=team_name)
- return reverse('dtracker-team-update', kwargs={
- 'slug': team.slug,
- })
- def get_subscriptions_url(self):
- return reverse('dtracker-accounts-subscriptions')
- def assert_team_packages_equal(self, team, package_names):
- team_package_names = [p.name for p in team.packages.all()]
- self.assertEqual(len(package_names), len(team_package_names))
- for package_name in package_names:
- self.assertIn(package_name, team_package_names)
- def log_in(self, user=None, password=None):
- """
- Helper method which logs the user in, without taking any shortcuts (it
- goes through the steps to fill in the form and submit it).
- """
- if user is None:
- user = self.user
- if password is None:
- password = self.password
- self.get_page(self.get_login_url())
- self.input_to_element('id_username', user.main_email)
- self.input_to_element('id_password', password)
- self.send_enter('id_password')
- def log_out(self):
- """
- Logs the currently logged in user out.
- """
- self.browser.find_element_by_id("account-logout").click()
- def test_create_team(self):
- """
- Tests that a logged in user can create a new team.
- """
- # The user tries going to the page to create a new team
- self.get_page(self.get_create_team_url())
- # However, the browser is not signed in so the response
- # redirects to the login page.
- self.assertIn(self.get_login_url(), self.browser.current_url)
- self.wait_response(1)
- # The user then logs in
- self.log_in()
- # ...and tries again
- self.get_page(self.get_create_team_url())
- # This time the response page has a form to create a new team.
- self.assert_element_with_id_in_page('create-team-form')
- # The user forgets to input the team name, initially.
- self.send_enter('id_name')
- # Since a name is required, an error is returned
- self.assert_in_page_body('This field is required')
- # The user inputs the team name, but not a maintainer email
- team_name = 'New team'
- self.input_to_element('id_name', team_name)
- self.send_enter('id_name')
- self.wait_response(1)
- # The user is now redirected to the team's page
- self.assert_current_url_equal(self.get_team_url(team_name))
- # === The team actually exists ===
- self.assertEqual(1, Team.objects.filter(name=team_name).count())
- # === The user is its owner ===
- team = Team.objects.get(name=team_name)
- self.assertEqual(self.user, team.owner)
- # The user goes back to the team creation page now
- self.get_page(self.get_create_team_url())
- # They try creating a new team with the same name
- self.input_to_element('id_name', team_name)
- self.send_enter('id_name')
- # This time, the team creation process fails because the team name is
- # not unique.
- self.assert_in_page_body('Team with this Name already exists')
- def test_create_team_maintainer_email(self):
- """
- Tests creating a team with a maintainer email set.
- The team should become automatically associated with the maintainer's
- packages.
- """
- # === Set up some packages maintained by the same maintainer ===
- package_names = [
- 'pkg1',
- 'pkg2',
- ]
- maintainer_email = 'maintainer@domain.com'
- maintainer = ContributorName.objects.create(
- contributor_email=UserEmail.objects.create(
- email=maintainer_email))
- for package_name in package_names:
- SourcePackage.objects.create(
- source_package_name=SourcePackageName.objects.create(
- name=package_name),
- version='1.0.0',
- maintainer=maintainer)
- # === Create a package with no maintainer ===
- SourcePackageName.objects.create(name='dummy-package')
- # === -- ===
- # The user logs in and accesses the create team page.
- self.log_in()
- self.get_page(self.get_create_team_url())
- # They input both the team name and the maintaner name.
- team_name = 'Team name'
- self.input_to_element('id_name', team_name)
- self.input_to_element('id_maintainer_email', maintainer_email)
- self.send_enter('id_maintainer_email')
- self.wait_response(1)
- # The team is successfully created and the user can see the
- # maintainer's packages already in the team's page
- for package_name in package_names:
- self.assert_in_page_body(package_name)
- # === The team really is associated with the packages? ===
- team = Team.objects.all()[0]
- self.assert_team_packages_equal(team, package_names)
- # The user now wants to associate the team with a different maintainer
- # that maintains other packages
- new_package_name = 'pkg3'
- new_maintainer_email = 'new-maintainer@domain.com'
- new_maintainer = ContributorName.objects.create(
- contributor_email=UserEmail.objects.create(
- email=new_maintainer_email))
- SourcePackage.objects.create(
- source_package_name=SourcePackageName.objects.create(
- name=new_package_name),
- version='1.0.0',
- maintainer=new_maintainer)
- self.get_element_by_id('update-team-button').click()
- # The user modifies the maintainer field
- self.clear_element_text('id_maintainer_email')
- self.input_to_element('id_maintainer_email', new_maintainer_email)
- self.send_enter('id_maintainer_email')
- self.wait_response(1)
- # The user is directed back to the team page which shows all the
- # packages previously associated with the team, as well as the ones
- # associated to the new maintainer.
- self.assert_in_page_body(new_package_name)
- for package_name in package_names:
- self.assert_in_page_body(package_name)
- # === The team is really associated with all these packages? ===
- self.assert_team_packages_equal(
- team, package_names + [new_package_name])
- def test_delete_team(self):
- """
- Tests that the owner can delete a team.
- """
- # === Set up a team owned by the user ===
- team_name = 'Team name'
- Team.objects.create_with_slug(owner=self.user, name=team_name)
- # Before logging in the user opens the team page
- self.get_page(self.get_team_url(team_name))
- # The page does not show the delete button.
- self.assert_not_in_page_body("Delete")
- # The user goes directly to the deletion URL.
- self.get_page(self.get_delete_team_url(team_name))
- # But permission is denied to the user
- self.assert_not_in_page_body(team_name)
- # The user now logs in.
- self.log_in()
- self.get_page(self.get_team_url(team_name))
- # The delete button is now offered to the user
- self.assert_element_with_id_in_page('delete-team-button')
- # So the user decides to click it.
- self.get_element_by_id('delete-team-button').click()
- self.wait_response(1)
- # The response shows a popup asking to confirm the team deletion.
- cancel_button = self.get_element_by_id('team-delete-cancel-button')
- confirm_button = self.get_element_by_id('confirm-team-delete-button')
- self.assertTrue(confirm_button.is_displayed())
- self.assertTrue(cancel_button.is_displayed())
- # The user decides to cancel the deletion
- cancel_button.click()
- self.wait_response(1)
- # The response is the team page and the team has not been deleted.
- self.assert_current_url_equal(self.get_team_url(team_name))
- # === The team is still here ===
- self.assertEqual(1, Team.objects.count())
- # The user now deletes the team.
- self.get_element_by_id('delete-team-button').click()
- self.wait_response(1)
- self.get_element_by_id('confirm-team-delete-button').click()
- self.wait_response(1)
- # The response page confirms the team has been successfully
- # deleted.
- self.assert_current_url_equal(self.get_team_deleted_url())
- # === The team is also really deleted? ===
- self.assertEqual(0, Team.objects.count())
- def test_update_team(self):
- """
- Tests that the team owner can update the team's basic info.
- """
- # === Set up a team owned by the user ===
- team_name = 'Team name'
- Team.objects.create_with_slug(owner=self.user, name=team_name)
- # Before logging in the user opens the team page
- self.get_page(self.get_team_url(team_name))
- # The page does not show the update button.
- self.assert_not_in_page_body("Update")
- # The user goes directly to the update URL.
- self.get_page(self.get_update_team_url(team_name))
- # But permission is denied to the user
- self.assert_not_in_page_body(team_name)
- # The user now logs in
- self.log_in()
- self.get_page(self.get_team_url(team_name))
- # The page now shows the update button
- self.assert_element_with_id_in_page('update-team-button')
- # The user clocks the link to update the team information.
- self.get_element_by_id('update-team-button').click()
- # The response page is the update page now...
- self.assert_current_url_equal(self.get_update_team_url(team_name))
- # ... with a form to update the team's info.
- self.assert_element_with_id_in_page('update-team-form')
- # The user modifies the team's description
- new_description = "This is a new description"
- self.input_to_element('id_description', new_description)
- self.send_enter('id_name')
- self.wait_response(1)
- # The user is taken back to the team's page
- self.assert_current_url_equal(self.get_team_url(team_name))
- # The updated information is displayed in the page already
- self.assert_in_page_body(new_description)
- # === The team's info is actually updated? ===
- team = Team.objects.all()[0]
- self.assertEqual(new_description, team.description)
- # The user now wants to update the team's name without affecting the
- # team's URL.
- old_url = self.get_team_url(team_name)
- self.get_element_by_id('update-team-button').click()
- self.clear_element_text('id_name')
- new_name = team_name + ' new name'
- self.input_to_element('id_name', new_name)
- self.send_enter('id_name')
- self.wait_response(1)
- # The user is now found back at the team page which contains the
- # updated name
- self.assert_in_page_body(new_name)
- # However, the package's URL is still the same
- self.assert_current_url_equal(old_url)
- # Now the user wants to modify the team's url without modifying its
- # name.
- self.get_element_by_id('update-team-button').click()
- old_slug = team.slug
- self.clear_element_text('id_slug')
- new_slug = old_slug + '-new-slug'
- self.input_to_element('id_slug', new_slug)
- self.send_enter('id_slug')
- self.wait_response(1)
- # The user is once again back on the team page.
- # The URL has been modified now to contain the new team slug.
- self.assertIn(new_slug, self.browser.current_url)
- # === The slug really is updated? ===
- self.assertEqual(new_slug, Team.objects.all()[0].slug)
- def test_package_management(self):
- """
- Tests that adding/removing packages from the team works as expected.
- """
- # === Set up a team owned by the user ===
- team_name = 'Team name'
- team = Team.objects.create_with_slug(owner=self.user, name=team_name)
- # === Set up some packages which the user can add to the team ===
- package_names = [
- 'pkg1',
- 'pkg2',
- ]
- for package_name in package_names:
- PackageName.objects.create(name=package_name)
- # === -- ===
- # The user opens the team page without logging in
- self.get_page(self.get_team_url(team_name))
- # The page does not show the form to add a package.
- form = self.get_element_by_id('add-team-package-form')
- self.assertIsNone(form)
- # The user logs in and opens the team page
- self.log_in()
- self.get_page(self.get_team_url(team_name))
- # The response page shows the form to add packages now.
- self.assert_element_with_id_in_page('add-team-package-form')
- # The user enters the name of the package to add...
- self.input_to_element('id_package_name', package_names[0])
- # ...and submits the form.
- self.send_enter('id_package_name')
- self.wait_response(1)
- # The user is still in the team page
- self.assert_current_url_equal(self.get_team_url(team_name))
- # The page now shows the package they added in the list of packages.
- self.assert_in_page_body(package_names[0])
- # The user tries adding a new package: one that does not exist.
- self.input_to_element('id_package_name', 'this-does-not-exist')
- self.send_enter('id_package_name')
- self.wait_response(1)
- # The user is still in the team page, but nothing is changed when it
- # comes to the list of packages.
- self.assert_not_in_page_body('this-does-not-exist')
- # The user now wants to remove the package from the team.
- # They click the button to remove the package from the team.
- remove_button = self.browser.find_element_by_css_selector(
- '.remove-package-from-team-button')
- remove_button.click()
- self.wait_response(1)
- # A popup is displayed asking the user to confirm the removal
- # The user decides to cancel the operation
- self.get_element_by_id('remove-package-cancel-button').click()
- self.wait_response(1)
- # The response is still the team page, and the package is not removed.
- self.assert_current_url_equal(self.get_team_url(team_name))
- # === The package is not removed? ===
- self.assertEqual(1, team.packages.count())
- # The user decides to definitely remove the package now
- remove_button.click()
- self.wait_response(1)
- self.get_element_by_id('confirm-remove-package-button').click()
- self.wait_response(1)
- # The user is still on the team page, but the package is not longer
- # a part of the team.
- self.assert_current_url_equal(self.get_team_url(team_name))
- self.assert_not_in_page_body(package_names[0])
- # === The package is really removed from the team ===
- self.assertEqual(0, team.packages.count())
- def test_team_access(self):
- """
- Tests joining and leaving a team.
- """
- # === Set up a team and a user who isn't the owner of the team ===
- team_name = 'Team name'
- team = Team.objects.create_with_slug(owner=self.user, name=team_name)
- user = User.objects.create_user(
- main_email='other@domain.com',
- password=self.password)
- UserEmail.objects.get_or_create(email=user.main_email)
- # === end setup ===
- # The user logs in and goes to the team page
- self.log_in(user)
- self.get_page(self.get_team_url(team_name))
- # The page shows a button to join the team.
- self.assert_element_with_id_in_page('join-team-button')
- # ... so the user clicks it.
- self.get_element_by_id('join-team-button').click()
- self.wait_response(1)
- # The response is still the team page, but now the user is a
- # member of the team.
- self.assert_element_with_id_in_page('add-team-package-form')
- # === The user is really a member? ===
- self.assertTrue(team.user_is_member(user))
- # The page now has a button to leave the team.
- self.assert_element_with_id_in_page('leave-team-button')
- # So the user clicks that button.
- self.get_element_by_id('leave-team-button').click()
- self.wait_response(1)
- # The user is now again not a member of the team
- self.assert_element_with_id_in_page('join-team-button')
- # === The user really isn't a member any more. ===
- self.assertFalse(team.user_is_member(user))
- # The user now logs out
- self.log_out()
- # And tries clicking the join team button
- self.get_element_by_id('join-team-button').click()
- self.wait_response(1)
- # But the response redirects to the login page.
- self.assert_element_with_id_in_page('form-login')
- # === The privacy of the team is switched to private. ===
- team.public = False
- team.save()
- # When the user opens the page again, the join button is replaced with
- # a link to contact the owner.
- self.get_page(self.get_team_url(team_name))
- self.assert_in_page_body('Contact the owner')
- def test_owner_members_management(self):
- """
- Tests that a team owner is able to add/remove members from a separate
- panel.
- """
- team_name = 'Team name'
- Team.objects.create_with_slug(owner=self.user, name=team_name)
- self.log_in()
- self.get_page(self.get_team_url(team_name))
- # The user opens the member management page
- self.get_element_by_id('manage-team-button').click()
- # The user wants to add a new team member
- new_team_member = 'member@domain.com'
- self.input_to_element('id_email', new_team_member)
- self.send_enter('id_email')
- self.wait_response(1)
- # The user is still in the same page, but can see the new member in the
- # list of all members
- self.assert_in_page_body(new_team_member)
- # === The membership is marked muted, though ===
- membership = TeamMembership.objects.all()[0]
- self.assertTrue(membership.muted)
- # === Email was sent to the new member asking for confirmation ===
- self.assertEqual(1, len(mail.outbox))
- self.assertIn(new_team_member, mail.outbox[0].to)
- # The user now decides to remove the team member
- button = \
- self.browser.find_element_by_css_selector('.remove-user-button')
- button.click()
- self.wait_response(1)
- # The user is no longer a part of the team
- self.assert_not_in_page_body(new_team_member)
- def test_toggle_team_mute(self):
- """
- Tests that a team member is able to mute and unmute a team membership
- from the subscription details page.
- """
- # === -- ===
- team_name = 'Team name'
- team = Team.objects.create_with_slug(owner=self.user, name=team_name)
- membership = team.add_members([self.user.emails.all()[0]])[0]
- # === -- ===
- # The user logs in and goes to their subscriptions page.
- self.log_in()
- self.get_page(self.get_subscriptions_url())
- # The response page shows a button to mute the team membership.
- self.assert_in_page_body('Mute')
- # The user clicks the button.
- btn = self.get_element_by_class('toggle-team-mute')
- btn.click()
- self.wait_response(1)
- # The response page is still the team page, and shows a
- # warning that the user's team membership is muted.
- self.assert_element_with_class_in_page('mute-warning')
- # === The membership is actually muted? ===
- membership = TeamMembership.objects.get(pk=membership.pk)
- self.assertTrue(membership.muted)
- # The user now wants to revert this.
- # The page shows the unmute button.
- self.assert_in_page_body('Unmute')
- # The user clicks the button.
- btn = self.get_element_by_class('toggle-team-mute')
- btn.click()
- self.wait_response(1)
- # Once again, the user is still in the subscriptions page, but the
- # button has reverted back to the mute button
- self.assert_in_page_body('Mute')
- # And the warning is gone
- self.assertIsNone(self.get_element_by_class('mute-warning'))
|