def test_remove_link_not_shown_if_no_duplicate(self): with person_logged_in(self.bug_owner): view = create_initialized_view(self.bug.default_bugtask, name="+duplicate", principal=self.bug_owner) soup = BeautifulSoup(view.render()) self.assertIsNone(soup.find(attrs={'id': 'field.actions.remove'}))
def test_blog_posts(self): """Posts from the launchpad blog are shown when feature is enabled""" self.useFixture(FeatureFixture({'app.root_blog.enabled': True})) posts = [ self._make_blog_post(1, "A post", "Post contents.", "2002"), self._make_blog_post(2, "Another post", "More contents.", "2003"), ] calls = [] def _get_blog_posts(): calls.append('called') return posts root = getUtility(ILaunchpadRoot) with anonymous_logged_in(): view = create_initialized_view(root, 'index.html') view.getRecentBlogPosts = _get_blog_posts result = view() markup = BeautifulSoup( result, parse_only=SoupStrainer(id='homepage-blogposts')) self.assertEqual(['called'], calls) items = markup.findAll('li', 'news') # Notice about launchpad being opened is always added at the end self.assertEqual(3, len(items)) a = items[-1].find("a") self.assertEqual("Launchpad now open source", a.string.strip()) for post, item in zip(posts, items): a = item.find("a") self.assertEqual(post['link'], a["href"]) self.assertEqual(post['title'], a.string)
def test_ajax_remove_duplicate(self): # An ajax request to remove a duplicate returns the new bugtask table. with person_logged_in(self.bug_owner): self.bug.markAsDuplicate(self.duplicate_bug) extra = { 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest', } form = { 'field.actions.remove': u'Remove Duplicate', } view = create_initialized_view(self.bug.default_bugtask, name="+duplicate", principal=self.bug_owner, form=form, **extra) result_html = view.render() self.assertIsNone(self.bug.duplicateof) self.assertEqual(view.request.response.getHeader('content-type'), 'text/html') soup = BeautifulSoup(result_html) table = soup.find('table', { 'id': 'affected-software', 'class': 'listing' }) self.assertIsNotNone(table)
def test_user_without_launchpad_view(self): # When the user does not have launchpad.View on the context, # base-layout does not render the main slot and side slot. owner = self.factory.makePerson() with person_logged_in(owner): team = self.factory.makeTeam(displayname='Waffles', owner=owner, visibility=PersonVisibility.PRIVATE) archive = self.factory.makeArchive(private=True, owner=team) archive.newSubscription(self.user, registrant=owner) with person_logged_in(self.user): view = self.makeTemplateView('main_side', context=team) content = BeautifulSoup(view()) self.assertIs(None, content.find(text=' Extra head content ')) self.verify_base_layout_html_element(content) self.verify_base_layout_head_parts(view, content) document = find_tag_by_id(content, 'document') self.verify_base_layout_body_parts(document) self.verify_watermark(document) # These parts are unique to the case without launchpad.View. self.assertIsNone(document.find(True, id='side-portlets')) self.assertIsNone(document.find(True, id='registration')) self.assertEndsWith( extract_text(document.find(True, id='maincontent')), 'The information in this page is not shared with you.')
def test_bug_description_in_meta_description_anonymous(self): browser = self.getBrowserForBugWithEmail(no_login=True) soup = BeautifulSoup(browser.contents) meat = soup.find('meta', dict(name='description')) self.assertThat(meat['content'], MatchesAll( Contains('Description with'), Not(Contains('@')), Contains('...'))) # Ellipsis from hidden address.
def test_information_type_vocabulary(self): # Test that the view creates the vocabulary correctly. bug = self.factory.makeBug() with person_logged_in(bug.owner): view = create_initialized_view(bug.default_bugtask, name='+secrecy', principal=bug.owner) html = view.render() soup = BeautifulSoup(html) self.assertEqual(u'Private', soup.find('label', text="Private").string)
def test_bug_description_in_meta_description_not_anonymous(self): browser = self.getBrowserForBugWithEmail(no_login=False) soup = BeautifulSoup(browser.contents) meat = soup.find('meta', dict(name='description')) # Even logged in users get email stripped from the metadata, in case # they use a tool that copies it out. self.assertThat(meat['content'], MatchesAll( Contains('Description with'), Not(Contains('@')), Contains('...'))) # Ellipsis from hidden address.
def test_featured_projects_manage_link_requires_edit(self): self.setUpRegistryExpert() view = create_initialized_view(self.root, 'index.html', principal=self.expert) # Stub out the getRecentBlogPosts which fetches a blog feed using # urlfetch. view.getRecentBlogPosts = lambda: [] content = BeautifulSoup(view(), parse_only=SoupStrainer('a')) self.assertTrue( content.find('a', href='+featuredprojects'), "Cannot find the +featuredprojects link on the first page")
def test_has_logo_without_watermark(self): root = getUtility(ILaunchpadRoot) user = self.factory.makePerson() login_person(user) view = create_initialized_view(root, 'index.html', principal=user) # Replace the blog posts so the view does not make a network request. view.getRecentBlogPosts = lambda: [] markup = BeautifulSoup(view(), parse_only=SoupStrainer(id='document')) self.assertIs(False, view.has_watermark) self.assertIs(None, markup.find(True, id='watermark')) logo = markup.find(True, id='launchpad-logo-and-name') self.assertIsNot(None, logo) self.assertEqual('/@@/launchpad-logo-and-name.png', logo['src'])
def test_job_notifications_display_multiple_is_capped(self): jobs = [self.makeJob('package%d' % i) for i in range(7)] with person_logged_in(self.archive.owner): view = create_initialized_view(self.archive, "+packages", principal=self.archive.owner) soup = BeautifulSoup(view.render()) self.assertEqual([], soup.findAll('div', attrs={ 'class': 'pending-job', 'job_id': jobs[-1].id })) showing_tags = soup.find_all('span', text=re.compile('Showing 5 of .')) self.assertEqual(['Showing 5 of 7'], [tag.string for tag in showing_tags])
def test_blog_posts_with_memcache(self): self.useFixture(FeatureFixture({'app.root_blog.enabled': True})) posts = [ self._make_blog_post(1, "A post", "Post contents.", "2002"), self._make_blog_post(2, "Another post", "More contents.", "2003"), ] key = '%s:homepage-blog-posts' % config.instance_name getUtility(IMemcacheClient).set(key, posts) root = getUtility(ILaunchpadRoot) with anonymous_logged_in(): view = create_initialized_view(root, 'index.html') result = view() markup = BeautifulSoup( result, parse_only=SoupStrainer(id='homepage-blogposts')) items = markup.findAll('li', 'news') self.assertEqual(3, len(items))
def test_blog_disabled(self): """Launchpad blog not queried for display without feature""" calls = [] def _get_blog_posts(): calls.append('called') return [] root = getUtility(ILaunchpadRoot) user = self.factory.makePerson() login_person(user) view = create_initialized_view(root, 'index.html', principal=user) view.getRecentBlogPosts = _get_blog_posts markup = BeautifulSoup(view(), parse_only=SoupStrainer(id='homepage')) self.assertEqual([], calls) self.assertIs(None, markup.find(True, id='homepage-blogposts')) # Even logged in users should get the launchpad intro text in the left # column rather than blank space when the blog is not being displayed. self.assertTrue(view.show_whatslaunchpad) self.assertTrue(markup.find(True, 'homepage-whatslaunchpad'))
def test_main_side(self): # The main_side layout has everything. view = self.makeTemplateView('main_side') content = BeautifulSoup(view()) self.assertIsNot(None, content.find(text=' Extra head content ')) self.verify_base_layout_html_element(content) self.verify_base_layout_head_parts(view, content) document = find_tag_by_id(content, 'document') self.verify_base_layout_body_parts(document) classes = 'tab-overview main_side public yui3-skin-sam'.split() self.assertEqual(classes, document['class']) self.verify_watermark(document) self.assertEqual(['registering'], document.find(True, id='registration')['class']) self.assertEqual( 'Registered on 2005-09-16 by Illuminati', document.find(True, id='registration').string.strip(), ) self.assertEndsWith( extract_text(document.find(True, id='maincontent')), 'Main content of the page.') self.assertEqual(['yui-b', 'side'], document.find(True, id='side-portlets')['class']) self.assertEqual('form', document.find(True, id='globalsearch').name)
def findQuestionTitle(self, response): """Find the question title field in an XHTML document fragment.""" soup = BeautifulSoup(response.body) dt = soup.find('dt', text="title") dd = dt.findNextSibling('dd') return str(dd.contents.pop())
def _hasCSSClass(self, html, element_id, css_class): # Return True if element with ID `element_id` in `html` has # a CSS class `css_class`. soup = BeautifulSoup(html) element = soup.find(attrs={'id': element_id}) return css_class in element.get('class', [])
def findBugDescription(self, response): """Find the bug description field in an XHTML document fragment.""" soup = BeautifulSoup(response.body) dt = soup.find('dt', text="description") dd = dt.findNextSibling('dd') return str(dd.contents.pop())