def test_footer_for_mergeable_and_non_admin(self): """A mortal sees a Reply link for a comment on a mergeable MP.""" comment = self.makeCodeReviewComment() display_comment = CodeReviewDisplayComment(comment) browser = self.getViewBrowser(display_comment) footer = Tag('comment footer', 'div', {'class': 'boardCommentFooter'}) hide_link = Tag('hide link', 'a', text=re.compile(r'\s*Hide\s*')) reply_link = Tag('reply link', 'a', text='Reply') self.assertThat(browser.contents, Not(HTMLContains(hide_link))) self.assertThat(browser.contents, HTMLContains(reply_link.within(footer)))
def test_footer_for_non_mergeable_and_admin(self): """An admin sees a Hide link for a comment on a non-mergeable MP.""" comment = self.makeCodeReviewComment() merge_proposal = comment.branch_merge_proposal with person_logged_in(merge_proposal.registrant): merge_proposal.markAsMerged( merge_reporter=merge_proposal.registrant) display_comment = CodeReviewDisplayComment(comment) browser = self.getViewBrowser(display_comment, user=self.factory.makeAdministrator()) footer = Tag('comment footer', 'div', {'class': 'boardCommentFooter'}) hide_link = Tag('hide link', 'a', text=re.compile(r'\s*Hide\s*')) reply_link = Tag('reply link', 'a', text='Reply') self.assertThat(browser.contents, HTMLContains(hide_link.within(footer))) self.assertThat(browser.contents, Not(HTMLContains(reply_link)))
def test_short_comment_no_download_link(self): """Long comments displayed by themselves are not truncated.""" comment = self.factory.makeCodeReviewComment(body='x ' * 5000) download_url = canonical_url(comment, view_name='+download') browser = self.getViewBrowser(comment) body = Tag('Download', 'a', {'href': download_url}, text='Download full text') self.assertThat(browser.contents, Not(HTMLContains(body)))
def test_configure_answers_skips_launchpad_for_proprietary(self): # Proprietary projects forbid LAUNCHPAD for answers. for info_type in PROPRIETARY_INFORMATION_TYPES: product = self.factory.makeProduct(information_type=info_type) with person_logged_in(None): browser = self.getViewBrowser( product, '+configure-answers', user=removeSecurityProxy(product).owner) self.assertThat(browser.contents, Not(HTMLContains(self.lp_tag)))
def test_private_dupes_not_linked_without_permission(self): bug = self.factory.makeBug() publidupe = self.factory.makeBug() visidupe = self.factory.makeBug( information_type=InformationType.PRIVATESECURITY) invisidupe = self.factory.makeBug( information_type=InformationType.PRIVATESECURITY) with admin_logged_in(): publidupe.markAsDuplicate(bug) visidupe.markAsDuplicate(bug) invisidupe.markAsDuplicate(bug) visidupe.subscribe(bug.owner, visidupe.owner) with person_logged_in(bug.owner): getUtility(IOpenLaunchBag).add(bug.default_bugtask) html = create_initialized_view(bug.default_bugtask, "+index", principal=bug.owner)() # The public dupe and subscribed private dupe are listed, but # the unsubscribed one is not. dupes_portlet = Tag("dupes portlet", "div", attrs={"id": "portlet-duplicates"}) self.assertThat( html, MatchesAll( HTMLContains( Within( dupes_portlet, Tag("public dupe", "a", text=re.compile("Bug #%d" % publidupe.id), attrs={"class": "sprite bug"})), Within( dupes_portlet, Tag("private dupe", "a", text=re.compile("Bug #%d" % visidupe.id), attrs={"class": "sprite bug private"}))), Not( HTMLContains( Tag("invisible dupe", "a", text=re.compile("Bug #%d" % invisidupe.id))))))
def test_has_batch_navigation(self): # The page has the usual batch navigation links. with person_logged_in(self.p3a_owner): view = create_initialized_view( self.private_ppa, '+subscriptions', principal=self.p3a_owner) html = view.render() has_batch_navigation = HTMLContains( Tag('batch navigation links', 'td', attrs={'class': 'batch-navigation-links'}, count=2)) self.assertThat(html, has_batch_navigation)
def test_register_upstream_forbids_proprietary(self): # Cannot specify information_type if registering for sourcepackage. sourcepackage = self.factory.makeSourcePackage() browser = self.getViewBrowser(sourcepackage) browser.getControl("Register the upstream project").click() browser.getControl("Link to Upstream Project").click() browser.getControl("Summary").value = "summary" browser.getControl("Continue").click() t = Tag('info_type', 'input', attrs={'name': 'field.information_type'}) self.assertThat(browser.contents, Not(HTMLContains(t)))
def test_no_footer_for_non_mergeable_and_non_admin(self): """A mortal sees no footer for a comment on a non-mergeable MP.""" comment = self.makeCodeReviewComment() merge_proposal = comment.branch_merge_proposal with person_logged_in(merge_proposal.registrant): merge_proposal.markAsMerged( merge_reporter=merge_proposal.registrant) display_comment = CodeReviewDisplayComment(comment) browser = self.getViewBrowser(display_comment) footer = Tag('comment footer', 'div', {'class': 'boardCommentFooter'}) self.assertThat(browser.contents, Not(HTMLContains(footer)))
def test_bug_canonical_url(self): bug = self.factory.makeBug() browser = self.getViewBrowser(bug, rootsite="bugs") # Hardcode this to be sure we've really got what we expected, with no # confusion about lp's own url generation machinery. expected_url = 'http://bugs.launchpad.dev/bugs/%d' % bug.id self.assertThat( browser.contents, HTMLContains( Tag('link rel=canonical', 'link', dict(rel='canonical', href=expected_url))))
def test_comment_page_has_meta_description(self): # The CodeReviewDisplayComment class provides IComment. with person_logged_in(self.factory.makePerson()): comment = self.factory.makeCodeReviewComment() display_comment = CodeReviewDisplayComment(comment) browser = self.getViewBrowser(display_comment) self.assertThat( browser.contents, HTMLContains( Tag('meta description', 'meta', dict(name='description', content=comment.message_body))))
def test_search_macro_title(self): # The title text is displayed for the macro `simple-search-form`. product = self.factory.makeProduct(displayname='Test Product', official_malone=True) view = create_initialized_view(product, '+bugs') self.assertEqual('Search bugs in Test Product', view.search_macro_title) # The title is shown. form_title_matches = Tag('Search form title', 'h3', text=view.search_macro_title) view = create_initialized_view(product, '+bugs') self.assertThat(view.render(), HTMLContains(form_title_matches))
def test_search_macro_css_for_form_node(self): # The <form> node has the CSS classes # "primary search dynamic_bug_listing". product = self.factory.makeProduct(displayname='Test Product', official_malone=True) attributes = { 'name': 'search', 'class': 'primary search dynamic_bug_listing', } search_form_matches = Tag('Search form CSS classes', tag_type='form', attrs=attributes) view = create_initialized_view(product, '+bugs') self.assertThat(view.render(), HTMLContains(search_form_matches))
def test_multiple_info_type_errors(self): # Multiple information type errors are presented at once. product = self.factory.makeProduct() self.factory.makeBranch(product=product) self.factory.makeSpecification(product=product) browser = self.getViewBrowser(product, '+edit', user=product.owner) info_type = browser.getControl(name='field.information_type') info_type.value = ['PROPRIETARY'] browser.getControl('Change').click() tag = Tag('error', 'div', attrs={'class': 'message'}, text='Some blueprints are public. ' 'Some branches are neither proprietary nor embargoed.') self.assertThat(browser.contents, HTMLContains(tag))
def test_search_macro_div_node_with_css_class(self): # The <div> enclosing the search form in the macro # `simple-search-form` has the CSS class "dynamic_bug_listing". product = self.factory.makeProduct(displayname='Test Product', official_malone=True) attributes = { 'id': 'bugs-search-form', 'class': 'dynamic_bug_listing', } search_div_with_class_attribute_matches = Tag('Main search div', tag_type='div', attrs=attributes) view = create_initialized_view(product, '+bugs') self.assertThat(view.render(), HTMLContains(search_div_with_class_attribute_matches))
def test_bug_comment_metadata(self): owner = self.factory.makePerson() login_person(owner) bug_comment = self.factory.makeBugComment() browser = self.getViewBrowser(bug_comment) iso_date = bug_comment.datecreated.isoformat() self.assertThat( browser.contents, HTMLContains(Tag( 'comment time tag', 'time', attrs=dict( itemprop='commentTime', title=True, datetime=iso_date))))
def test_change_information_type_proprietary_packaged(self): # It should be an error to make a Product private if it is packaged. product = self.factory.makeProduct() sourcepackage = self.factory.makeSourcePackage() sourcepackage.setPackaging(product.development_focus, product.owner) browser = self.getViewBrowser(product, '+edit', user=product.owner) info_type = browser.getControl(name='field.information_type') info_type.value = ['PROPRIETARY'] old_url = browser.url browser.getControl('Change').click() self.assertEqual(old_url, browser.url) tag = Tag('error', 'div', text='Some series are packaged.', attrs={'class': 'message'}) self.assertThat(browser.contents, HTMLContains(tag))
def test_link_upstream_handles_proprietary(self): # Proprietary products produce an 'invalid value' error. owner = self.factory.makePerson() product = self.factory.makeProduct(owner=owner) product_name = product.name product_displayname = product.displayname sourcepackage = self.factory.makeSourcePackage( sourcepackagename=product_name) with person_logged_in(None): browser = self.getViewBrowser(sourcepackage, user=owner) with person_logged_in(owner): product.information_type = InformationType.PROPRIETARY browser.getControl(product_displayname).click() browser.getControl("Link to Upstream Project").click() error = Tag( 'error', 'div', attrs={'class': 'message'}, text='Invalid value') self.assertThat(browser.contents, HTMLContains(error)) self.assertNotIn( 'The project %s was linked to this source package.' % str(product_displayname), browser.contents)
def hasAutoImport(value): tag = Tag('importall', 'input', attrs={'name': 'field.translations_autoimport_mode', 'value': value}) return HTMLContains(tag)
def test_long_comments_not_truncated(self): """Long comments displayed by themselves are not truncated.""" comment = self.factory.makeCodeReviewComment(body='x y' * 2000) browser = self.getViewBrowser(comment) body = Tag('Body text', 'p', text='x y' * 2000) self.assertThat(browser.contents, HTMLContains(body))
def hasLink(url): return HTMLContains(Tag('link', 'a', attrs={'href': url}))
def test_configure_answers_has_launchpad_for_public(self): # Public projects support LAUNCHPAD for answers. browser = self.getViewBrowser(self.product, '+configure-answers', user=self.product.owner) self.assertThat(browser.contents, HTMLContains(self.lp_tag))