class LandingViewsTest(test_utils.TestCase): fixtures = ['test_data.json', ] def setUp(self): self.client = LocalizingClient() def test_home(self): url = reverse('landing.views.home') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mozilla(self): url = reverse('landing.views.mozilla') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_web(self): url = reverse('landing.views.web') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_search(self): raise SkipTest('Search test disabled until we switch to kuma wiki') url = reverse('landing.views.search') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_promote_buttons(self): url = reverse('landing.views.promote_buttons') r = self.client.get(url, follow=True) eq_(200, r.status_code)
class DemoListViewsTest(test_utils.TestCase): fixtures = ['test_users.json'] def setUp(self): self.user, self.admin_user, self.other_user = make_users() self.client = LocalizingClient() def test_all_demos_includes_hidden_for_staff(self): build_submission(self.user) build_hidden_submission(self.user) r = self.client.get(reverse('demos_all')) count = pq(r.content)('h2.count').text() eq_(count, "1 Demo") self.client.login(username=self.admin_user.username, password='******') r = self.client.get(reverse('demos_all')) count = pq(r.content)('h2.count').text() eq_(count, "2 Demos") @attr('bug882709') def test_search_view(self): try: self.client.get(reverse('demos_search')) except: self.fail("Search should not ISE.")
def test_kumawiki_waffle_flag(self): # Turn off the new wiki for everyone self.kumawiki_flag.everyone = False self.kumawiki_flag.save() client = LocalizingClient() resp = client.get(reverse('wiki.all_documents')) eq_(404, resp.status_code) resp = client.get(reverse('docs')) page = pq(resp.content) eq_(0, page.find('#kumawiki_preview').length) client.login(username='******', password='******') # Turn on the wiki for just superusers, ignore everyone else self.kumawiki_flag.superusers = True self.kumawiki_flag.everyone = None self.kumawiki_flag.save() resp = client.get(reverse('wiki.all_documents')) eq_(200, resp.status_code) resp = client.get(reverse('docs')) page = pq(resp.content) eq_(1, page.find('#kumawiki_preview').length)
class LandingViewsTest(test_utils.TestCase): fixtures = ["test_data.json"] def setUp(self): self.client = LocalizingClient() def test_home(self): url = reverse("landing.views.home") r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) dev_mdc_link = doc.find("a#dev-mdc-link") ok_(dev_mdc_link) def test_mozilla(self): url = reverse("landing.views.mozilla") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_web(self): url = reverse("landing.views.web") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_search(self): raise SkipTest("Search test disabled until we switch to kuma wiki") url = reverse("landing.views.search") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_promote_buttons(self): url = reverse("landing.views.promote_buttons") r = self.client.get(url, follow=True) eq_(200, r.status_code)
class EventsViewsTest(test_utils.TestCase): fixtures = ["devmo_calendar.json"] def setUp(self): self.client = LocalizingClient() devmo_calendar_reload() def test_events(self): url = reverse("devmo.views.events") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_events_map_flag(self): url = reverse("devmo.views.events") r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_([], doc.find("#map_canvas")) ok_("maps.google.com" not in r.content) events_map_flag = Flag.objects.create(name="events_map", everyone=True) events_map_flag.save() r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_(1, len(doc.find("#map_canvas"))) ok_("maps.google.com" in r.content)
class HomeTests(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_social_promo(self): url = reverse('landing.views.home') aurora_promo, social_promo = get_promos(self.client, url) ok_(aurora_promo) ok_(not social_promo) Switch.objects.create(name="social_promo", active=True) aurora_promo, social_promo = get_promos(self.client, url) ok_(not aurora_promo) ok_(social_promo) def test_google_analytics(self): url = reverse('landing.views.home') constance.config.GOOGLE_ANALYTICS_ACCOUNT = '' r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' not in r.content) constance.config.GOOGLE_ANALYTICS_ACCOUNT = 'UA-99999999-9' r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' in r.content)
class EventsViewsTest(test_utils.TestCase): fixtures = ['devmo_calendar.json'] def setUp(self): self.client = LocalizingClient() devmo_calendar_reload() def test_events(self): url = reverse('devmo.views.events') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_events_map_flag(self): url = reverse('devmo.views.events') r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_([], doc.find('#map_canvas')) ok_("maps.google.com" not in r.content) events_map_flag = Flag.objects.create(name='events_map', everyone=True) events_map_flag.save() r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_(1, len(doc.find('#map_canvas'))) ok_("maps.google.com" in r.content)
class AppsViewsTest(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_apps_menu_item(self): url = reverse("landing.views.home") r = self.client.get(url) eq_(200, r.status_code) doc = pq(r.content) nav_sub_topics = doc.find("ul#nav-sub-topics") ok_(nav_sub_topics) apps_item = nav_sub_topics.find("li#nav-sub-apps") eq_("Apps", apps_item.text()) def test_apps(self): url = reverse("landing.views.apps") r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) signup_form = doc.find("form.fm-subscribe") eq_(reverse("apps_subscription", locale="en-US"), signup_form.attr("action")) @patch("landing.views.basket.subscribe") def test_apps_subscription(self, subscribe): subscribe.return_value = True url = reverse("landing.views.apps_subscription") r = self.client.post(url, {"format": "html", "email": "*****@*****.**", "agree": "checked"}, follow=True) eq_(200, r.status_code) # assert thank you message self.assertContains(r, "Thank you") eq_(1, subscribe.call_count) @patch("landing.views.basket.subscribe") def test_apps_subscription_ajax(self, subscribe): subscribe.return_value = True url = reverse("landing.views.apps_subscription") r = self.client.post( url, {"format": "html", "email": "*****@*****.**", "agree": "checked"}, HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) eq_(200, r.status_code) # assert thank you message self.assertContains(r, "Thank you") self.assertNotContains(r, "<html") self.assertNotContains(r, "<head>") self.assertNotContains(r, "<title>") eq_(1, subscribe.call_count) @patch("landing.views.basket.subscribe") def test_apps_subscription_bad_values(self, subscribe): subscribe.return_value = True url = reverse("landing.views.apps_subscription") r = self.client.post(url, {"format": 1, "email": "nope"}) eq_(200, r.status_code) # assert error self.assertContains(r, "Enter a valid e-mail address.") self.assertContains(r, "Select a valid choice.") self.assertContains(r, "You must agree to the privacy policy.")
def test_json_callback_validation(self): """Various json callbacks -- validation""" c = LocalizingClient() q = 'bookmarks' format = 'json' callbacks = ( ('callback', 200), ('validCallback', 200), ('obj.method', 200), ('obj.someMethod', 200), ('arr[1]', 200), ('arr[12]', 200), ("alert('xss');foo", 400), ("eval('nastycode')", 400), ("someFunc()", 400), ('x', 200), ('x123', 200), ('$', 200), ('_func', 200), ('"></script><script>alert(\'xss\')</script>', 400), ('">', 400), ('var x=something;foo', 400), ('var x=', 400), ) for callback, status in callbacks: response = c.get(reverse('search'), { 'q': q, 'format': format, 'callback': callback, }) eq_(response['Content-Type'], 'application/x-javascript') eq_(response.status_code, status)
class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @attr('docs_activity') @attr('bug715923') @patch('devmo.models.UserDocsActivityFeed.fetch_user_feed') def test_bug715923_feed_parsing_errors(self, fetch_user_feed): fetch_user_feed.return_value = """ THIS IS NOT EVEN XML, SO BROKEN """ try: profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username, )) r = self.client.get(url, follow=True) pq(r.content) except Exception, e: raise e ok_(False, "There should be no exception %s" % e)
def test_review_tags(self): client = LocalizingClient() client.login(username='******', password='******') data = new_document_data() data.update({'review_tags':['editorial']}) response = client.post(reverse('wiki.new_document'), data) doc = Document.objects.get(slug="a-test-article") combos = ( ([], 0, 0, 0, 0), (['technical',], 1, 1, 0, 0), (['editorial',], 0, 0, 1, 1), (['technical', 'editorial',], 1, 1, 1, 1), ) for tags, a, b, c, d in combos: # Edit the page and set the tags for this test data.update({ 'form': 'rev', 'review_tags': tags }) response = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) response = client.get(reverse('docs.views.docs')) page = pq(response.content) # Check for the section itself, and then the doc eq_(a, page('div#review-technical').length) eq_(b, page("div#review-technical ul li h4 a:contains('%s')" % doc.title).length) eq_(c, page('div#review-editorial').length) eq_(d, page("div#review-editorial ul li h4 a:contains('%s')" % doc.title).length)
def test_raw_section_source(self): """The raw source for a document section can be requested""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) expected = """ <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> """ response = client.get('%s?section=s2&raw=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def test_raw_with_editing_links_source(self): """The raw source for a document can be requested, with section editing links""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) expected = """ <h1 id="s1"><a class="edit-section" data-section-id="s1" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s1" href="/en-US/docs/%(slug)s$edit?section=s1&edit_links=true" title="Edit section">Edit</a>Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2"><a class="edit-section" data-section-id="s2" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s2" href="/en-US/docs/%(slug)s$edit?section=s2&edit_links=true" title="Edit section">Edit</a>Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3"><a class="edit-section" data-section-id="s3" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s3" href="/en-US/docs/%(slug)s$edit?section=s3&edit_links=true" title="Edit section">Edit</a>Head 3</h1> <p>test</p> <p>test</p> """ % {'slug': d.slug} response = client.get('%s?raw=true&edit_links=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def test_raw_with_editing_links_source(self): """The raw source for a document can be requested, with section editing links""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) expected = """ <h1 id="s1"><a class="edit-section" data-section-id="s1" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s1" href="/en-US/docs/%(slug)s$edit?section=s1&edit_links=true" title="Edit section">Edit</a>Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2"><a class="edit-section" data-section-id="s2" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s2" href="/en-US/docs/%(slug)s$edit?section=s2&edit_links=true" title="Edit section">Edit</a>Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3"><a class="edit-section" data-section-id="s3" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s3" href="/en-US/docs/%(slug)s$edit?section=s3&edit_links=true" title="Edit section">Edit</a>Head 3</h1> <p>test</p> <p>test</p> """ % { 'slug': d.slug } response = client.get('%s?raw=true&edit_links=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @attr('docs_activity') @attr('bug715923') @patch('devmo.models.UserDocsActivityFeed.fetch_user_feed') def test_bug715923_feed_parsing_errors(self, fetch_user_feed): fetch_user_feed.return_value = """ THIS IS NOT EVEN XML, SO BROKEN """ try: profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) pq(r.content) except Exception, e: raise e ok_(False, "There should be no exception %s" % e)
class HomeTests(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_google_analytics(self): url = reverse('landing.views.home') with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT='0'): r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' not in r.content) with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT='UA-99999999-9'): r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' in r.content)
def test_json_format(self): """JSON without callback should return application/json""" c = LocalizingClient() response = c.get(reverse('search'), { 'q': 'bookmarks', 'format': 'json', }) eq_(response['Content-Type'], 'application/json')
def test_breadcrumb(): """Make sure breadcrumb links start with /.""" c = LocalizingClient() response = c.get(reverse('search')) doc = pq(response.content) href = doc('.breadcrumbs a')[0] eq_('/', href.attrib['href'][0])
def test_ban_middleware(self): """Ban middleware functions correctly.""" client = LocalizingClient() client.login(username='******', password='******') resp = client.get('/') self.assertTemplateNotUsed(resp, 'users/user_banned.html') admin = User.objects.get(username='******') testuser = User.objects.get(username='******') ban = UserBan(user=testuser, by=admin, reason='Banned by unit test.', is_active=True) ban.save() resp = client.get('/') self.assertTemplateUsed(resp, 'users/user_banned.html')
def test_breadcrumb(): """Make sure breadcrumb links start with /.""" c = LocalizingClient() response = c.get(reverse("search")) doc = pq(response.content) href = doc(".breadcrumbs a")[0] eq_("/", href.attrib["href"][0])
def test_ban_permission(self): """The ban permission controls access to the ban view.""" client = LocalizingClient() admin = User.objects.get(username="******") testuser = User.objects.get(username="******") # testuser doesn't have ban permission, can't ban. client.login(username="******", password="******") ban_url = reverse("users.ban_user", kwargs={"user_id": admin.id}) resp = client.get(ban_url) eq_(302, resp.status_code) ok_(settings.LOGIN_URL in resp["Location"]) client.logout() # admin has ban permission, can ban. client.login(username="******", password="******") ban_url = reverse("users.ban_user", kwargs={"user_id": testuser.id}) resp = client.get(ban_url) eq_(200, resp.status_code)
def test_ban_permission(self): """The ban permission controls access to the ban view.""" client = LocalizingClient() admin = User.objects.get(username='******') testuser = User.objects.get(username='******') # testuser doesn't have ban permission, can't ban. client.login(username='******', password='******') ban_url = reverse('users.ban_user', kwargs={'user_id': admin.id}) resp = client.get(ban_url) eq_(302, resp.status_code) ok_(settings.LOGIN_URL in resp['Location']) client.logout() # admin has ban permission, can ban. client.login(username='******', password='******') ban_url = reverse('users.ban_user', kwargs={'user_id': testuser.id}) resp = client.get(ban_url) eq_(200, resp.status_code)
def test_edit_midair_collision(self): client = LocalizingClient() client.login(username='******', password='******') # Post a new document. data = new_document_data() resp = client.post(reverse('wiki.new_document'), data) doc = Document.objects.get(slug=data['slug']) # Edit #1 starts... resp = client.get(reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get(reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': 'This edit got there first', 'current_rev': rev_id2 }) resp = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but receives a mid-aired notification data.update({ 'form': 'rev', 'content': 'This edit gets mid-aired', 'current_rev': rev_id1 }) resp = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) eq_(200, resp.status_code) ok_( unicode(MIDAIR_COLLISION).encode('utf-8') in resp.content, "Midair collision message should appear")
def test_json_empty_query(self): """Empty query returns JSON format""" c = LocalizingClient() # Test with flags for advanced search or not a_types = (0, 1, 2) for a in a_types: response = c.get(reverse('search'), { 'format': 'json', 'a': a, }) eq_(response['Content-Type'], 'application/json')
class EventsViewsTest(test_utils.TestCase): fixtures = ['devmo_calendar.json'] def setUp(self): self.client = LocalizingClient() devmo_calendar_reload() def test_events(self): url = reverse('devmo.views.events') r = self.client.get(url, follow=True) eq_(200, r.status_code)
class LandingViewsTest(test_utils.TestCase): fixtures = [ 'test_data.json', ] def setUp(self): self.client = LocalizingClient() def test_home(self): url = reverse('landing.views.home') r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) dev_mdc_link = doc.find('a#dev-mdc-link') ok_(dev_mdc_link) def test_addons(self): url = reverse('landing.views.addons') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mozilla(self): url = reverse('landing.views.mozilla') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mobile(self): url = reverse('landing.views.mobile') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_web(self): url = reverse('landing.views.web') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_promote_buttons(self): url = reverse('landing.views.promote_buttons') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_discussion(self): url = reverse('landing.views.discussion') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_forum_archive(self): url = reverse('landing.views.forum_archive') r = self.client.get(url, follow=True) eq_(200, r.status_code)
class HomeTests(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_social_promo(self): url = reverse('landing.views.home') promo = get_promos(self.client, url, '#promo-fosdev') ok_(promo) def test_google_analytics(self): url = reverse('landing.views.home') constance.config.GOOGLE_ANALYTICS_ACCOUNT = '' r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' not in r.content) constance.config.GOOGLE_ANALYTICS_ACCOUNT = 'UA-99999999-9' r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' in r.content)
class HomeTests(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_social_promo(self): url = reverse("landing.views.home") promo = get_promos(self.client, url, "#promo-fosdev") ok_(promo) def test_google_analytics(self): url = reverse("landing.views.home") with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT="0"): r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_("var _gaq" not in r.content) with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT="UA-99999999-9"): r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_("var _gaq" in r.content)
class LearnViewsTest(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_learn(self): url = reverse("landing.views.learn") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_html(self): url = reverse("landing.views.learn_html") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_html5(self): url = reverse("landing.views.learn_html5") r = self.client.get(url, follow=True) eq_(404, r.status_code) s = Switch.objects.create(name="html5_landing", active=True) s.save() r = self.client.get(url, follow=True) eq_(200, r.status_code) s.delete() def test_learn_css(self): url = reverse("landing.views.learn_css") r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_javascript(self): url = reverse("landing.views.learn_javascript") r = self.client.get(url, follow=True) eq_(200, r.status_code)
class LearnViewsTest(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_learn(self): url = reverse('landing.views.learn') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_html(self): url = reverse('landing.views.learn_html') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_html5(self): url = reverse('landing.views.learn_html5') r = self.client.get(url, follow=True) eq_(404, r.status_code) s = Switch.objects.create(name='html5_landing', active=True) s.save() r = self.client.get(url, follow=True) eq_(200, r.status_code) s.delete() def test_learn_css(self): url = reverse('landing.views.learn_css') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_javascript(self): url = reverse('landing.views.learn_javascript') r = self.client.get(url, follow=True) eq_(200, r.status_code)
class HomeTests(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_social_promo(self): url = reverse('landing.views.home') promo = get_promos(self.client, url, '#promo-fosdev') ok_(promo) def test_google_analytics(self): url = reverse('landing.views.home') with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT='0'): r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' not in r.content) with override_constance_settings( GOOGLE_ANALYTICS_ACCOUNT='UA-99999999-9'): r = self.client.get(url, follow=True) eq_(200, r.status_code) ok_('var _gaq' in r.content)
def test_edit_midair_collision(self): client = LocalizingClient() client.login(username='******', password='******') # Post a new document. data = new_document_data() resp = client.post(reverse('wiki.new_document'), data) doc = Document.objects.get(slug=data['slug']) # Edit #1 starts... resp = client.get(reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get(reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': 'This edit got there first', 'current_rev': rev_id2 }) resp = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but receives a mid-aired notification data.update({ 'form': 'rev', 'content': 'This edit gets mid-aired', 'current_rev': rev_id1 }) resp = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) eq_(200, resp.status_code) ok_(unicode(MIDAIR_COLLISION).encode('utf-8') in resp.content, "Midair collision message should appear")
class LandingViewsTest(test_utils.TestCase): fixtures = ['test_data.json', ] def setUp(self): self.client = LocalizingClient() def test_home(self): url = reverse('landing.views.home') r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) dev_mdc_link = doc.find('a#dev-mdc-link') ok_(dev_mdc_link) def test_addons(self): url = reverse('landing.views.addons') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mozilla(self): url = reverse('landing.views.mozilla') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mobile(self): url = reverse('landing.views.mobile') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_web(self): url = reverse('landing.views.web') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_promote_buttons(self): url = reverse('landing.views.promote_buttons') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_discussion(self): url = reverse('landing.views.discussion') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_forum_archive(self): url = reverse('landing.views.forum_archive') r = self.client.get(url, follow=True) eq_(200, r.status_code)
class LearnViewsTest(test_utils.TestCase): def setUp(self): self.client = LocalizingClient() def test_learn(self): url = reverse('landing.views.learn') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_html(self): url = reverse('landing.views.learn_html') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_css(self): url = reverse('landing.views.learn_css') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_learn_javascript(self): url = reverse('landing.views.learn_javascript') r = self.client.get(url, follow=True) eq_(200, r.status_code)
class FilterTestCase(TestCase): def setUp(self): self.client = LocalizingClient() def _tweet_list(self, filter): """Return the content of async-fetched tweet list. Also, assert the request returns a 200. """ response = self.client.get(reverse('customercare.more_tweets'), {'filter': filter}) eq_(response.status_code, 200) return response.content
class FilterTestCase(TestCase): def setUp(self): self.client = LocalizingClient() def _tweet_list(self, filter): """Return the content of async-fetched tweet list. Also, assert the request returns a 200. """ response = self.client.get( reverse('customercare.more_tweets'), {'filter': filter}) eq_(response.status_code, 200) return response.content
def test_raw_section_edit(self): client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace = """ <h1 id="s2">Replace</h1> <p>replace</p> """ expected = """ <h1 id="s2">Replace</h1> <p>replace</p> """ response = client.post('%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[d.slug]), {"form": "rev", "content": replace}, follow=True) eq_(normalize_html(expected), normalize_html(response.content)) expected = """ <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Replace</h1> <p>replace</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """ response = client.get('%s?raw=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def test_raw_section_edit(self): client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace = """ <h1 id="s2">Replace</h1> <p>replace</p> """ expected = """ <h1 id="s2">Replace</h1> <p>replace</p> """ response = client.post('%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[d.slug]), { "form": "rev", "content": replace }, follow=True) eq_(normalize_html(expected), normalize_html(response.content)) expected = """ <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Replace</h1> <p>replace</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """ response = client.get('%s?raw=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def es_search_cmd(query, pages=1, log=log): """Simulates a front page search .. Note:: This **doesn't** simulate an advanced search---just a front page search. """ from sumo.tests import LocalizingClient from sumo.urlresolvers import reverse client = LocalizingClient() output = [] output.append('Search for: %s' % query) output.append('') data = { 'q': query, 'format': 'json' } url = reverse('search') # The search view shows 10 results at a time. So we hit it few # times---once for each page. for pageno in range(pages): pageno = pageno + 1 data['page'] = pageno resp = client.get(url, data) if resp.status_code != 200: output.append('ERROR: %s' % resp.content) break else: content = json.loads(resp.content) results = content[u'results'] for mem in results: output.append(u'%4d %5.2f %-10s %-20s' % ( mem['rank'], mem['score'], mem['type'], mem['title'])) output.append('') for line in output: log.info(line.encode('ascii', 'ignore'))
class LandingViewsTest(test_utils.TestCase): fixtures = [ 'test_data.json', ] def setUp(self): self.client = LocalizingClient() def test_home(self): url = reverse('landing.views.home') r = self.client.get(url, follow=True) eq_(200, r.status_code) doc = pq(r.content) dev_mdc_link = doc.find('a#dev-mdc-link') ok_(dev_mdc_link) def test_addons(self): url = reverse('landing.views.addons') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mozilla(self): url = reverse('landing.views.mozilla') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_mobile(self): url = reverse('landing.views.mobile') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_web(self): url = reverse('landing.views.web') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_search(self): raise SkipTest('Search test disabled until we switch to kuma wiki') url = reverse('landing.views.search') r = self.client.get(url, follow=True) eq_(200, r.status_code) def test_promote_buttons(self): url = reverse('landing.views.promote_buttons') r = self.client.get(url, follow=True) eq_(200, r.status_code)
def test_json_down(): """When the Sphinx is down, return JSON and 503 status""" c = LocalizingClient() # Test with flags for advanced search or not callbacks = ( ('', 503, 'application/json'), ('validCallback', 503, 'application/x-javascript'), # Invalid callback does not search ('eval("xss");a', 400, 'application/x-javascript'), ) for callback, status, mimetype in callbacks: response = c.get(reverse('search'), { 'q': 'json down', 'format': 'json', 'callback': callback, }) eq_(response['Content-Type'], mimetype) eq_(response.status_code, status)
def es_search_cmd(query, pages=1, log=log): """Simulates a front page search .. Note:: This **doesn't** simulate an advanced search---just a front page search. """ from sumo.tests import LocalizingClient from sumo.urlresolvers import reverse client = LocalizingClient() output = [] output.append('Search for: %s' % query) output.append('') data = {'q': query, 'format': 'json'} url = reverse('search') # The search view shows 10 results at a time. So we hit it few # times---once for each page. for pageno in range(pages): pageno = pageno + 1 data['page'] = pageno resp = client.get(url, data) if resp.status_code != 200: output.append('ERROR: %s' % resp.content) break else: content = json.loads(resp.content) results = content[u'results'] for mem in results: output.append( u'%4d %5.2f %-10s %-20s' % (mem['rank'], mem['score'], mem['type'], mem['title'])) output.append('') for line in output: log.info(line.encode('ascii', 'ignore'))
class DemoViewsTest(test_utils.TestCase): fixtures = ['test_users.json'] def setUp(self): self.testuser = User.objects.get(username='******') self.testuser.set_password(TESTUSER_PASSWORD) self.testuser.save() self.client = LocalizingClient() def test_submit_loggedout(self): r = self.client.get(reverse('demos_submit')) choices = pq(r.content)('p.choices a[href*="login"]') eq_(choices.length, 1) @logged_in def test_submit_loggedin(self): r = self.client.get(reverse('demos_submit')) assert pq(r.content)('form#demo-submit') @logged_in def test_submit_post_invalid(self): r = self.client.post(reverse('demos_submit'), data={}) d = pq(r.content) assert d('form#demo-submit') assert d('li#field_title ul.errorlist') assert d('li#field_summary ul.errorlist') assert d('li#field_screenshot_1 ul.errorlist') assert d('li#field_demo_package ul.errorlist') assert d('li#field_license_name ul.errorlist') assert d('li#field_captcha ul.errorlist') assert d('li#field_accept_terms ul.errorlist') @logged_in @disable_captcha def test_submit_post_valid(self): # Create a valid demo zip file zf_fout = StringIO() zf = zipfile.ZipFile(zf_fout, 'w') zf.writestr('index.html', """<html></html>""") zf.close() # Create a new file for input zf_fin = StringIO(zf_fout.getvalue()) zf_fin.name = 'demo.zip' r = self.client.post(reverse('demos_submit'), data=dict( title='Test submission', summary='This is a test demo submission', description='Some description goes here', tech_tags=( 'tech:audio', 'tech:video', 'tech:websockets', ), screenshot_1=open(SCREENSHOT_PATH), demo_package=zf_fin, license_name='gpl', accept_terms='1', )) eq_(302, r.status_code) assert 'Location' in r assert 'test-submission' in r['Location'] try: obj = Submission.objects.get(slug='test-submission') eq_('Test submission', obj.title) except Submission.DoesNotExist: assert False result_tags = [t.name for t in obj.taggit_tags.all_ns('tech:')] result_tags.sort() eq_(['tech:audio', 'tech:video', 'tech:websockets'], result_tags) @logged_in def test_edit_invalid(self): s = save_valid_submission() edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.post(edit_url, data=dict()) d = pq(r.content) assert d('form#demo-submit') assert d('li#field_title ul.errorlist') assert d('li#field_summary ul.errorlist') assert d('li#field_license_name ul.errorlist') @logged_in def test_edit_valid(self): s = save_valid_submission() edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.post(edit_url, data=dict( title=s.title, summary='This is a test demo submission', description='Some description goes here', tech_tags=( 'tech:audio', 'tech:video', 'tech:websockets', ), license_name='gpl', accept_terms='1', )) eq_(302, r.status_code) assert 'Location' in r assert 'hello-world' in r['Location'] try: obj = Submission.objects.get(slug='hello-world') eq_('This is a test demo submission', obj.summary) except Submission.DoesNotExist: assert False def test_detail(self): s = save_valid_submission('hello world') url = reverse('demos_detail', args=[s.slug]) r = self.client.get(url) d = pq(r.content) eq_(s.title, d('h1.page-title').text()) edit_link = d('ul.manage a.edit') assert not edit_link def test_detail_censored(self): s = save_valid_submission('hello world') s.censored = True s.save() url = reverse('demos_detail', args=[s.slug]) r = self.client.get(url) d = pq(r.content) eq_('Permission Denied', d('h1.page-title').text()) def test_detail_censored_url(self): s = save_valid_submission('hello world') s.censored = True s.censored_url = "http://developer.mozilla.org" s.save() url = reverse('demos_detail', args=[s.slug]) r = self.client.get(url) eq_(302, r.status_code) eq_("http://developer.mozilla.org", r['Location']) @logged_in def test_creator_can_edit(self): s = save_valid_submission('hello world') url = reverse('demos_detail', args=[s.slug]) r = self.client.get(url) d = pq(r.content) edit_link = d('ul#demo-manage a.edit') assert edit_link edit_url = reverse('demos_edit', args=[s.slug], locale='en-US') eq_(edit_url, edit_link.attr("href")) r = self.client.get(edit_url) assert pq(r.content)('form#demo-submit') eq_('Save changes', pq(r.content)('p.fm-submit button[type="submit"]').text()) @logged_in def test_hidden_field(self): s = save_valid_submission('hello world') edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.get(edit_url) assert pq(r.content)('input[name="hidden"][type="checkbox"]') @logged_in def test_derby_field(self): s = save_valid_submission('hello world') edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.get(edit_url) assert pq(r.content)('fieldset#devderby-submit') @logged_in def test_edit_no_tags(self): s = save_valid_submission('hello world') edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.post(edit_url, data=dict( title=s.title, summary='This is a test edit', description='Some description goes here', license_name='gpl', accept_terms='1', )) eq_(r.status_code, 302) r = self.client.get(edit_url) eq_(r.status_code, 200) @logged_in def test_edit_with_challenge_tag(self): s = save_valid_submission('hello world') edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.post( edit_url, data=dict( title=s.title, summary='This is a test edit', description='Some description goes here', tech_tags=('tech:audio', ), challenge_tags=parse_tags( constance.config.DEMOS_DEVDERBY_CHALLENGE_CHOICE_TAGS)[0], license_name='gpl', accept_terms='1', )) eq_(r.status_code, 302) r = self.client.get(edit_url) eq_(r.status_code, 200) def test_challenge_tag_to_date_parts(self): tag = 'challenge:2011:october' eq_(challenge_utils.challenge_tag_to_date_parts(tag), (2011, 10)) def test_challenge_tag_to_end_date(self): tag = 'challenge:2011:october' eq_(challenge_utils.challenge_tag_to_end_date(tag), datetime.date(2011, 10, 31)) tag = 'challenge:2011:february' eq_(challenge_utils.challenge_tag_to_end_date(tag), datetime.date(2011, 2, 28)) tag = 'challenge:2012:february' eq_(challenge_utils.challenge_tag_to_end_date(tag), datetime.date(2012, 2, 29)) def test_challenge_closed(self): open_tag = 'challenge:%s' % make_challenge_tag() closed_dt = datetime.date.today() - datetime.timedelta(days=32) closed_tag = 'challenge:%s' % closed_dt.strftime('%Y:%B').lower() assert not challenge_utils.challenge_closed([open_tag]) assert challenge_utils.challenge_closed([closed_tag]) def test_challenge_closed_model(self): s = save_valid_submission('hellow world') assert not s.challenge_closed() s.taggit_tags.set_ns('challenge:', make_challenge_tag()) assert not s.challenge_closed() closed_dt = datetime.date.today() - datetime.timedelta(days=32) s.taggit_tags.set_ns('challenge:', closed_dt.strftime('%Y:%B').lower()) assert s.challenge_closed() def test_derby_before_deadline(self): s = save_valid_submission('hello world') s.taggit_tags.set_ns('challenge:', make_challenge_tag()) form = SubmissionEditForm(instance=s) assert 'demo_package' in form.fields assert 'challenge_tags' in form.fields def test_derby_after_deadline(self): s = save_valid_submission('hello world') closed_dt = datetime.date.today() - datetime.timedelta(days=32) s.taggit_tags.set_ns('challenge:', closed_dt.strftime('%Y:%B').lower()) form = SubmissionEditForm(instance=s) assert 'demo_package' not in form.fields assert 'challenge_tags' not in form.fields @logged_in def test_derby_tag_saving(self): """ There's some tricky bits in the handling of editing and saving challenge tags; this test just exercises a cycle of edit/save a couple times in a row to make sure we don't go foul in there. """ s = save_valid_submission('hello world') closed_dt = datetime.date.today() - datetime.timedelta(days=32) s.taggit_tags.set_ns('challenge:', closed_dt.strftime('%Y:%B').lower()) edit_url = reverse('demos_edit', args=[s.slug]) r = self.client.get(edit_url) eq_(r.status_code, 200) r = self.client.post(edit_url, data=dict( title=s.title, summary='This is a test demo submission', description='Some description goes here', tech_tags=( 'tech:audio', 'tech:video', 'tech:websockets', ), license_name='gpl', accept_terms='1', )) eq_(302, r.status_code) assert 'Location' in r assert s.slug in r['Location'] r = self.client.get(edit_url) eq_(r.status_code, 200) r = self.client.post(edit_url, data=dict( title=s.title, summary='This is a test demo submission', description='Some description goes here', tech_tags=( 'tech:audio', 'tech:video', 'tech:websockets', ), license_name='gpl', accept_terms='1', )) eq_(302, r.status_code) assert 'Location' in r assert s.slug in r['Location'] r = self.client.get(edit_url) eq_(r.status_code, 200) @attr('bug702156') def test_bug_702156(self): """Demo with missing screenshots should not cause exceptions in views""" # Create the submission... s = save_valid_submission('hello world') s.taggit_tags.set_ns('tech:', 'javascript') s.featured = True s.save() # Ensure the new screenshot and thumbnail URL code works when there's a # screenshot present. try: r = self.client.get(reverse('demos_all')) r = self.client.get(reverse('demos_tag', args=['tech:javascript'])) r = self.client.get(reverse('demos_detail', args=[s.slug])) r = self.client.get(reverse('demos_feed_recent', args=['atom'])) r = self.client.get(reverse('demos_feed_featured', args=['json'])) except: ok_(False, "No exceptions should have been thrown") # Forcibly delete the screenshot - should not be possible from # user-facing UI per form validation, but we should at least not throw # exceptions. s.screenshot_1.storage.delete(s.screenshot_1.name) s.screenshot_1 = None s.save() # Big bucks, no whammies... try: r = self.client.get(reverse('demos_all')) r = self.client.get(reverse('demos_tag', args=['tech:javascript'])) r = self.client.get(reverse('demos_detail', args=[s.slug])) r = self.client.get(reverse('demos_feed_recent', args=['atom'])) r = self.client.get(reverse('demos_feed_featured', args=['json'])) except: ok_(False, "No exceptions should have been thrown") @attr('bug745902') def test_long_slug(self): """ A title longer than 50 characters should truncate to a 50-character slug during (python-level) save, not on DB insertion, so that anything that wants the slug to build a URL has the value that actually ends up in the DB. """ s = save_valid_submission( "AudioVisualizer for Alternative Music Notation Systems") s.taggit_tags.set_ns('tech:', 'javascript') s.save() ok_(len(s.slug) == 50) r = self.client.get(reverse('demos.views.detail', args=(s.slug, ))) ok_(r.status_code == 200) @attr('bug781823') def test_unicode(self): """ Unicode characters in the summary or description doesn't brick the feed. """ s = save_valid_submission('ΦOTOS ftw', 'ΦOTOS ΦOTOS ΦOTOS') s.featured = 1 s.save() r = self.client.get(reverse('demos_feed_featured', args=['json'])) ok_(r.status_code == 200) def test_make_unique_slug(self): """ Ensure that unique slugs are generated even from titles whose first 50 characters are identical. """ s = save_valid_submission( "This is a really long title whose only purpose in life is to be longer than fifty characters" ) s2 = save_valid_submission( "This is a really long title whose only purpose in life is to be longer than fifty characters and not the same as the first title" ) s3 = save_valid_submission( "This is a really long title whose only purpose in life is to be longer than fifty characters and not the same as the first or second title" ) ok_(s.slug != s2.slug and s.slug != s3.slug and s2.slug != s3.slug)
def test_review_tags(self, get_current): get_current.return_value.domain = 'su.mo.com' """Review tags can be managed on document revisions""" client = LocalizingClient() client.login(username='******', password='******') # Create a new doc with one review tag data = new_document_data() data.update({'review_tags': ['technical']}) response = client.post(reverse('wiki.new_document'), data) # Ensure there's now a doc with that expected tag in its newest # revision doc = Document.objects.get(slug="a-test-article") rev = doc.revisions.order_by('-id').all()[0] review_tags = [x.name for x in rev.review_tags.all()] eq_(['technical'], review_tags) # Now, post an update with two tags data.update({ 'form': 'rev', 'review_tags': ['editorial', 'technical'], }) response = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) # Ensure the doc's newest revision has both tags. doc = Document.objects.get(slug="a-test-article") rev = doc.revisions.order_by('-id').all()[0] review_tags = [x.name for x in rev.review_tags.all()] review_tags.sort() eq_(['editorial', 'technical'], review_tags) # Now, ensure that warning boxes appear for the review tags. response = client.get(reverse('wiki.document', args=[doc.slug]), data) page = pq(response.content) eq_(1, page.find('.warning.review-technical').length) eq_(1, page.find('.warning.review-editorial').length) # Ensure the page appears on the listing pages response = client.get(reverse('wiki.list_review')) eq_( 1, pq(response.content).find("ul.documents li a:contains('%s')" % doc.title).length) response = client.get( reverse('wiki.list_review_tag', args=('technical', ))) eq_( 1, pq(response.content).find("ul.documents li a:contains('%s')" % doc.title).length) response = client.get( reverse('wiki.list_review_tag', args=('editorial', ))) eq_( 1, pq(response.content).find("ul.documents li a:contains('%s')" % doc.title).length) # Also, ensure that the page appears in the proper feeds # HACK: Too lazy to parse the XML. Lazy lazy. response = client.get( reverse('wiki.feeds.list_review', args=('atom', ))) ok_('<entry><title>%s</title>' % doc.title in response.content) response = client.get( reverse('wiki.feeds.list_review_tag', args=( 'atom', 'technical', ))) ok_('<entry><title>%s</title>' % doc.title in response.content) response = client.get( reverse('wiki.feeds.list_review_tag', args=( 'atom', 'editorial', ))) ok_('<entry><title>%s</title>' % doc.title in response.content) # Post an edit that removes one of the tags. data.update({ 'form': 'rev', 'review_tags': [ 'editorial', ], }) response = client.post(reverse('wiki.edit_document', args=[doc.slug]), data) # Ensure only one of the tags' warning boxes appears, now. response = client.get(reverse('wiki.document', args=[doc.slug]), data) page = pq(response.content) eq_(0, page.find('.warning.review-technical').length) eq_(1, page.find('.warning.review-editorial').length) # Ensure the page appears on the listing pages response = client.get(reverse('wiki.list_review')) eq_( 1, pq(response.content).find("ul.documents li a:contains('%s')" % doc.title).length) response = client.get( reverse('wiki.list_review_tag', args=('technical', ))) eq_( 0, pq(response.content).find("ul.documents li a:contains('%s')" % doc.title).length) response = client.get( reverse('wiki.list_review_tag', args=('editorial', ))) eq_( 1, pq(response.content).find("ul.documents li a:contains('%s')" % doc.title).length) # Also, ensure that the page appears in the proper feeds # HACK: Too lazy to parse the XML. Lazy lazy. response = client.get( reverse('wiki.feeds.list_review', args=('atom', ))) ok_('<entry><title>%s</title>' % doc.title in response.content) response = client.get( reverse('wiki.feeds.list_review_tag', args=( 'atom', 'technical', ))) ok_('<entry><title>%s</title>' % doc.title not in response.content) response = client.get( reverse('wiki.feeds.list_review_tag', args=( 'atom', 'editorial', ))) ok_('<entry><title>%s</title>' % doc.title in response.content)
def test_midair_section_collision(self): """If both a revision and the edited section has changed, then a section edit is a collision.""" client = LocalizingClient() client.login(username='******', password='******') doc, rev = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace_1 = """ <h1 id="s2">replace</h1> <p>replace</p> """ replace_2 = """ <h1 id="s2">first replace</h1> <p>first replace</p> """ data = {'form': 'rev', 'content': rev.content} # Edit #1 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': replace_2, 'current_rev': rev_id2 }) resp = client.post( '%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but since it's the same section, there's a collision data.update({ 'form': 'rev', 'content': replace_1, 'current_rev': rev_id1 }) resp = client.post( '%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) # With the raw API, we should get a 409 Conflict on collision. eq_(409, resp.status_code)
def test_midair_section_merge(self): """If a page was changed while someone was editing, but the changes didn't affect the specific section being edited, then ignore the midair warning""" client = LocalizingClient() client.login(username='******', password='******') doc, rev = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace_1 = """ <h1 id="s1">replace</h1> <p>replace</p> """ replace_2 = """ <h1 id="s2">replace</h1> <p>replace</p> """ expected = """ <h1 id="s1">replace</h1> <p>replace</p> <h1 id="s2">replace</h1> <p>replace</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """ data = {'form': 'rev', 'content': rev.content} # Edit #1 starts... resp = client.get('%s?section=s1' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': replace_2, 'current_rev': rev_id2 }) resp = client.post( '%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but since it's a different section, there's no # mid-air collision data.update({ 'form': 'rev', 'content': replace_1, 'current_rev': rev_id1 }) resp = client.post( '%s?section=s1&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) # No conflict, but we should get a 205 Reset as an indication that the # page needs a refresh. eq_(205, resp.status_code) # Finally, make sure that all the edits landed response = client.get('%s?raw=true' % reverse('wiki.document', args=[doc.slug])) eq_(normalize_html(expected), normalize_html(response.content)) # Also, ensure that the revision is slipped into the headers eq_(unicode(Document.uncached.get(slug=doc.slug).current_revision.id), unicode(response['x-kuma-revision']))
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******', 'next': login_uri }, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login') def test_mindtouch_disabled_login(self, mock_mindtouch_login): """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth.""" # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_mindtouch_login(username, password, force=False): trap['was_called'] = True return False mock_mindtouch_login.side_effect = my_mindtouch_login # Try to log in as a MindTouch user, assert that MindTouch auth was # never attempted. _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) settings.DEKIWIKI_ENDPOINT = _old ok_(not trap['was_called']) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_mindtouch_creds_create_user_and_profile(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() get_current.return_value.domain = 'dev.mo.org' if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') self.assertRaises(User.DoesNotExist, User.objects.get, username='******') # Try to log in as a MindTouch user response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) # Ensure there are no validation errors page = pq(response.content) eq_(0, page.find('.errorlist').length, "There should be no validation errors in login") # Login should have auto-created django user u = User.objects.get(username='******') eq_(True, u.is_active) ok_(u.get_profile()) # Login page should show welcome back doc = pq(response.content) eq_('testaccount', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_request_properties(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' r = RequestFactory().get('/users/login', {'next': '/demos/submit'}, HTTP_REFERER='referer-trumped-by-get') eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().post('/users/login', {'next': '/demos/submit'}) eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().get('/users/login', HTTP_REFERER='/demos/submit') eq_('/demos/submit', _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_no_self_redirects(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' for next in [settings.LOGIN_URL, settings.LOGOUT_URL]: r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_invalid_next_parameter(self, get_current): '''_clean_next_url cleans invalid urls''' get_current.return_value.domain = 'dev.mo.org' for next in self._invalid_nexts(): r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_login_invalid_next_parameter(self, get_current): '''Test with an invalid ?next=http://example.com parameter.''' get_current.return_value.domain = 'testserver.com' valid_next = reverse('home', locale=settings.LANGUAGE_CODE) for invalid_next in self._invalid_nexts(): # Verify that _valid_ next parameter is set in form hidden field. response = self.client.get( urlparams(reverse('users.login'), next=invalid_next)) eq_(200, response.status_code) doc = pq(response.content) eq_(valid_next, doc('input[name="next"]')[0].attrib['value']) # Verify that it gets used on form POST. response = self.client.post( reverse('users.login'), { 'username': '******', 'password': '******', 'next': invalid_next }) eq_(302, response.status_code) eq_('http://testserver' + valid_next, response['location']) self.client.logout() def _invalid_nexts(self): return ['http://foobar.com/evil/', '//goo.gl/y-bad']
class BrowserIDTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): # Ensure @ssl_required goes unenforced. settings.DEBUG = True # Set up some easily-testable redirects. settings.LOGIN_REDIRECT_URL = 'SUCCESS' settings.LOGIN_REDIRECT_URL_FAILURE = 'FAILURE' # BrowserID will squawk if this isn't set settings.SITE_URL = 'http://testserver' self.client = LocalizingClient() def test_invalid_post(self): resp = self.client.post( reverse('users.browserid_verify', locale='en-US')) eq_(302, resp.status_code) ok_('FAILURE' in resp['Location']) @mock.patch('users.views._verify_browserid') def test_invalid_assertion(self, _verify_browserid): _verify_browserid.return_value = None resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'bad data'}) eq_(302, resp.status_code) ok_('FAILURE' in resp['Location']) @mock_get_deki_user_by_email @mock_put_mindtouch_user @mock_mindtouch_login @mock.patch('users.views._verify_browserid') def test_valid_assertion_with_django_user(self, _verify_browserid): _verify_browserid.return_value = {'email': '*****@*****.**'} # Posting the fake assertion to browserid_verify should work, with the # actual verification method mocked out. resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_(302, resp.status_code) ok_('SUCCESS' in resp['Location']) # The session should look logged in, now. ok_('_auth_user_id' in self.client.session.keys()) eq_('django_browserid.auth.BrowserIDBackend', self.client.session.get('_auth_user_backend', '')) @mock_get_deki_user_by_email @mock_put_mindtouch_user @mock_mindtouch_login @mock.patch('users.views._verify_browserid') def test_explain_popup(self, _verify_browserid): _verify_browserid.return_value = {'email': '*****@*****.**'} resp = self.client.get(reverse('home', locale='en-US')) # Posting the fake assertion to browserid_verify should work, with the # actual verification method mocked out. resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_('1', resp.cookies.get('browserid_explained').value) resp = self.client.get(reverse('users.logout'), locale='en-US') # even after logout, cookie should prevent the toggle resp = self.client.get(reverse('home', locale='en-US')) eq_('1', self.client.cookies.get('browserid_explained').value) @mock_get_deki_user_by_email @mock_put_mindtouch_user @mock_mindtouch_login @mock.patch('users.views._verify_browserid') def test_valid_assertion_with_mindtouch_user(self, _verify_browserid): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() mt_email = '*****@*****.**' _verify_browserid.return_value = {'email': mt_email} # Probably overkill but let's be sure we're testing the right thing. try: User.objects.get(email=mt_email) ok_(False, "The MindTouch user shouldn't exist in Django yet.") except User.DoesNotExist: pass if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) deki_user = DekiUserBackend.get_deki_user_by_email(mt_email) ok_(deki_user is not None, "The MindTouch user should exist") # Posting the fake assertion to browserid_verify should work, with the # actual verification method mocked out. resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_(302, resp.status_code) ok_('SUCCESS' in resp['Location']) # The session should look logged in, now. ok_('_auth_user_id' in self.client.session.keys()) eq_('django_browserid.auth.BrowserIDBackend', self.client.session.get('_auth_user_backend', '')) # And, after all the above, there should be a Django user now. try: User.objects.get(email=mt_email) except User.DoesNotExist: ok_(False, "The MindTouch user should exist in Django now.") @attr('current') @mock.patch('dekicompat.backends.DekiUserBackend.get_deki_user_by_email') @mock.patch('users.views._verify_browserid') def test_valid_assertion_with_mt_disabled(self, _verify_browserid, mock_get_deki_user_by_email): """On valid browserid assertion, when Django user is not found, yet MindTouch API disabled, there should be no attempt to look the user up in MindTouch""" mt_email = '*****@*****.**' _verify_browserid.return_value = {'email': mt_email} # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_get_deki_user_by_email(email): trap['was_called'] = True return False mock_get_deki_user_by_email.side_effect = my_get_deki_user_by_email _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) settings.DEKIWIKI_ENDPOINT = _old # This should end up being a redirect to register eq_(302, resp.status_code) ok_('browserid_register' in resp['Location']) ok_(not trap['was_called']) @mock_missing_get_deki_user_by_email @mock_missing_get_deki_user @mock_post_mindtouch_user @mock_put_mindtouch_user @mock_mindtouch_login @mock.patch('users.views._verify_browserid') def test_valid_assertion_with_new_account_creation(self, _verify_browserid): new_username = '******' new_email = '*****@*****.**' _verify_browserid.return_value = {'email': new_email} try: user = User.objects.get(email=new_email) ok_(False, "User for email should not yet exist") except User.DoesNotExist: pass if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: When not mocking the MindTouch API, ensure that there's no # leftover user with the same name & email as what we want to # register import random rand_num = random.randint(0, 1000000) user_xml = MINDTOUCH_USER_XML % dict(username="******" % (new_username, rand_num), email="%s_%s" % (rand_num, new_email), fullname="", status="inactive", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=%s' % new_username, user_xml=user_xml) # Sign in with a verified email, but with no existing account resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_(302, resp.status_code) # This should be a redirect to the BrowserID registration page. redir_url = resp['Location'] reg_url = reverse('users.browserid_register', locale='en-US') ok_(reg_url in redir_url) # And, as part of the redirect, the verified email address should be in # our session now. ok_(SESSION_VERIFIED_EMAIL in self.client.session.keys()) verified_email = self.client.session[SESSION_VERIFIED_EMAIL] eq_(new_email, verified_email) # Grab the redirect, assert that there's a create_user form present resp = self.client.get(redir_url) page = pq(resp.content) form = page.find('form#create_user') eq_(1, form.length) # There should be no error lists on first load eq_(0, page.find('.errorlist').length) # Submit the create_user form, with a chosen username resp = self.client.post(redir_url, { 'username': '******', 'action': 'register' }) # The submission should result in a redirect to the session's redirect # value eq_(302, resp.status_code) redir_url = resp['Location'] ok_('SUCCESS' in redir_url) # The session should look logged in, now. ok_('_auth_user_id' in self.client.session.keys()) eq_('django_browserid.auth.BrowserIDBackend', self.client.session.get('_auth_user_backend', '')) if settings.DEKIWIKI_ENDPOINT: ok_(self.client.cookies.get('authtoken'), 'Should have set ' 'authtoken cookie for ' 'MindTouch') # Ensure that the user was created, and with the submitted username and # verified email address try: user = User.objects.get(email=new_email) eq_(new_username, user.username) eq_(new_email, user.email) except User.DoesNotExist: ok_(False, "New user should have been created") @mock_missing_get_deki_user_by_email @mock_post_mindtouch_user @mock_put_mindtouch_user @mock_mindtouch_login @mock_get_deki_user @mock.patch('users.views._verify_browserid') def test_valid_assertion_with_existing_account_login( self, _verify_browserid): """ Removed the existing user form: we don't auth the password with MindTouch anymore """ new_email = '*****@*****.**' _verify_browserid.return_value = {'email': new_email} try: User.objects.get(email=new_email) ok_(False, "User for email should not yet exist") except User.DoesNotExist: pass # Sign in with a verified email, but with no existing account resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_(302, resp.status_code) # This should be a redirect to the BrowserID registration page. redir_url = resp['Location'] reg_url = reverse('users.browserid_register', locale='en-US') ok_(reg_url in redir_url) # And, as part of the redirect, the verified email address should be in # our session now. ok_(SESSION_VERIFIED_EMAIL in self.client.session.keys()) verified_email = self.client.session[SESSION_VERIFIED_EMAIL] eq_(new_email, verified_email) # Grab the redirect, assert that there's a create_user form present resp = self.client.get(redir_url) page = pq(resp.content) form = page.find('form#existing_user') eq_(0, form.length) @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login') @mock.patch('users.views._verify_browserid') def test_mindtouch_disabled_redirect_login(self, _verify_browserid, mock_mindtouch_login): """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth.""" _verify_browserid.return_value = {'email': '*****@*****.**'} # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_mindtouch_login(username, password, force=False): trap['was_called'] = True return False mock_mindtouch_login.side_effect = my_mindtouch_login _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False resp = self.client.post( reverse('users.browserid_verify', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) settings.DEKIWIKI_ENDPOINT = _old eq_(302, resp.status_code) ok_('SUCCESS' in resp['Location']) # The session should look logged in, now. ok_('_auth_user_id' in self.client.session.keys()) eq_('django_browserid.auth.BrowserIDBackend', self.client.session.get('_auth_user_backend', '')) ok_(not trap['was_called']) @mock_get_deki_user_by_email @mock_put_mindtouch_user @mock_mindtouch_login @mock.patch('users.views._verify_browserid') def test_valid_assertion_changing_email(self, _verify_browserid): # just need to be authenticated, not necessarily BrowserID self.client.login(username='******', password='******') _verify_browserid.return_value = {'email': '*****@*****.**'} resp = self.client.post( reverse('users.browserid_change_email', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_(302, resp.status_code) ok_('profiles/testuser/edit' in resp['Location']) resp = self.client.get( reverse('devmo_profile_edit', locale='en-US', args=[ 'testuser', ])) eq_(200, resp.status_code) doc = pq(resp.content) ok_('*****@*****.**' in doc.find('li#field_email').text()) @mock_get_deki_user_by_email @mock_put_mindtouch_user @mock_mindtouch_login @mock.patch('users.views._verify_browserid') def test_valid_assertion_doesnt_steal_email(self, _verify_browserid): # just need to be authenticated, not necessarily BrowserID self.client.login(username='******', password='******') _verify_browserid.return_value = {'email': '*****@*****.**'} # doesn't change email if the new email already belongs to another user resp = self.client.post( reverse('users.browserid_change_email', locale='en-US'), {'assertion': 'PRETENDTHISISVALID'}) eq_(302, resp.status_code) ok_('change_email' in resp['Location']) resp = self.client.get( reverse('devmo_profile_edit', locale='en-US', args=[ 'testuser', ])) eq_(200, resp.status_code) doc = pq(resp.content) ok_('*****@*****.**' in doc.find('li#field_email').text())
class ChangeEmailTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.client = LocalizingClient() @mock.patch_object(Site.objects, 'get_current') def test_user_change_email(self, get_current): """Send email to change user's email and then change it.""" get_current.return_value.domain = 'su.mo.com' self.client.login(username='******', password='******') # Attempt to change email. response = self.client.post(reverse('users.change_email'), {'email': '*****@*****.**'}, follow=True) eq_(200, response.status_code) # Be notified to click a confirmation link. eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 ec = EmailChange.objects.all()[0] assert ec.activation_key in mail.outbox[0].body eq_('*****@*****.**', ec.email) # Visit confirmation link to change email. response = self.client.get( reverse('users.confirm_email', args=[ec.activation_key])) eq_(200, response.status_code) u = User.objects.get(username='******') eq_('*****@*****.**', u.email) @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_user_change_email_updates_mindtouch(self, get_current): """Send email to change user's email and then change it.""" get_current.return_value.domain = 'su.mo.com' self.client.login(username='******', password='******') # Attempt to change email. response = self.client.post(reverse('users.change_email'), {'email': '*****@*****.**'}, follow=True) eq_(200, response.status_code) # Be notified to click a confirmation link. eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 ec = EmailChange.objects.all()[0] assert ec.activation_key in mail.outbox[0].body eq_('*****@*****.**', ec.email) # Visit confirmation link to change email. response = self.client.get( reverse('users.confirm_email', args=[ec.activation_key])) eq_(200, response.status_code) u = User.objects.get(username='******') eq_('*****@*****.**', u.email) if not settings.DEKIWIKI_MOCK: deki_id = u.get_profile().deki_user_id doc = get_deki_user_doc(u) eq_(str(deki_id), doc('user').attr('id')) eq_('*****@*****.**', doc('user').find('email').text()) def test_user_change_email_same(self): """Changing to same email shows validation error.""" self.client.login(username='******', password='******') user = User.objects.get(username='******') user.email = '*****@*****.**' user.save() response = self.client.post(reverse('users.change_email'), {'email': user.email}) eq_(200, response.status_code) doc = pq(response.content) eq_('This is your current email.', doc('ul.errorlist').text()) def test_user_change_email_duplicate(self): """Changing to same email shows validation error.""" self.client.login(username='******', password='******') email = '*****@*****.**' response = self.client.post(reverse('users.change_email'), {'email': email}) eq_(200, response.status_code) doc = pq(response.content) eq_('A user with that email address already exists.', doc('ul.errorlist').text()) @mock.patch_object(Site.objects, 'get_current') def test_user_confirm_email_duplicate(self, get_current): """If we detect a duplicate email when confirming an email change, don't change it and notify the user.""" get_current.return_value.domain = 'su.mo.com' self.client.login(username='******', password='******') old_email = User.objects.get(username='******').email new_email = '*****@*****.**' response = self.client.post(reverse('users.change_email'), {'email': new_email}) eq_(200, response.status_code) assert mail.outbox[0].subject.find('Please confirm your') == 0 ec = EmailChange.objects.all()[0] # Before new email is confirmed, give the same email to a user other_user = User.objects.filter(username='******')[0] other_user.email = new_email other_user.save() # Visit confirmation link and verify email wasn't changed. response = self.client.get( reverse('users.confirm_email', args=[ec.activation_key])) eq_(200, response.status_code) doc = pq(response.content) eq_('Unable to change email for user testuser', doc('.main h1').text()) u = User.objects.get(username='******') eq_(old_email, u.email)