def test_templates_program_detail_open_graph_description_program_excerpt_exceeds_max_length( self, ): """ The open graph description should be cut if it exceeds more than 200 caracters """ program = ProgramFactory() page = program.extended_object placeholder_value = ( "Long description that describes the page with a summary. " * 8) # Add a excerpt to a program placeholder = program.extended_object.placeholders.get( slot="program_excerpt") add_plugin( language="en", placeholder=placeholder, plugin_type="PlainTextPlugin", body=placeholder_value, ) page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) cut = placeholder_value[0:200] self.assertContains( response, f'<meta property="og:description" content="{cut}" />', )
def test_templates_program_detail_meta_description_program_excerpt_exceeds_max_length( self, ): """ The program meta description should show the program_excerpt if no meta_description is specified """ program = ProgramFactory() page = program.extended_object placeholder_value = ( "Long description that describes the page with a summary. " "Long description that describes the page with a summary. " "Long description that describes the page with a summary. ") # Add a excerpt to a program placeholder = program.extended_object.placeholders.get( slot="program_excerpt") add_plugin( language="en", placeholder=placeholder, plugin_type="PlainTextPlugin", body=placeholder_value, ) page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) cut = placeholder_value[0:160] self.assertContains( response, f'<meta name="description" content="{cut}" />', )
def test_cms_plugins_program_fallback_when_published_unpublished(self): """ The program plugin should not render when the program was voluntarily unpublished in the current language. """ # Create a program program = ProgramFactory( page_title={ "en": "public title", "fr": "titre public" }, fill_cover={ "original_filename": "cover.jpg", "default_alt_text": "my cover", }, ) program_page = program.extended_object # Create a page to add the plugin to page = create_i18n_page({"en": "A page", "fr": "Une page"}) placeholder = page.placeholders.get(slot="maincontent") add_plugin(placeholder, ProgramPlugin, "en", **{"page": program_page}) add_plugin(placeholder, ProgramPlugin, "fr", **{"page": program_page}) # Publish only the French version of the program program_page.publish("fr") program_page.publish("en") program_page.unpublish("en") # Check the page content in English page.publish("en") url = page.get_absolute_url(language="en") response = self.client.get(url) self.assertNotContains(response, "glimpse")
def test_cms_wizards_program_submit_form_slug_duplicate(self): """ Trying to create a program with a slug that would lead to a duplicate path should raise a validation error. """ # A parent page should pre-exist parent_page = create_page( "News", "richie/single_column.html", "en", reverse_id=Program.PAGE["reverse_id"], ) # Create an existing page with a known slug ProgramFactory(page_parent=parent_page, page_title="My title") # Submit a title that will lead to the same slug data = {"title": "my title"} user = UserFactory(is_staff=True, is_superuser=True) form = ProgramWizardForm(data=data, wizard_language="en", wizard_user=user) self.assertFalse(form.is_valid()) self.assertEqual(form.errors, {"slug": ["This slug is already in use"]})
def test_templates_program_detail_cms_no_course(self): """ Validate that a program without course doesn't show the course section on a published program page but does on the draft program page """ program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, ) page = program.extended_object # Publish the program and ensure the content is absent page.publish("en") url = page.get_absolute_url() response = self.client.get(url) self.assertNotContains( response, '<div class="program-detail__courses program-detail__block">') # The content should be visible as draft to the staff user user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") response = self.client.get(url) self.assertContains( response, '<div class="program-detail__courses program-detail__block">')
def test_templates_program_detail_cms_published_content_opengraph(self): """The program logo should be used as opengraph image.""" program = ProgramFactory( fill_cover={ "original_filename": "cover.jpg", "default_alt_text": "my cover", }, should_publish=True, ) url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, '<meta property="og:type" content="website" />') self.assertContains( response, f'<meta property="og:url" content="http://example.com{url:s}" />') pattern = ( r'<meta property="og:image" content="http://example.com' r"/media/filer_public_thumbnails/filer_public/.*cover\.jpg__1200x630" ) self.assertIsNotNone(re.search(pattern, str(response.content))) self.assertContains( response, '<meta property="og:image:width" content="1200" />') self.assertContains( response, '<meta property="og:image:height" content="630" />')
def test_templates_program_detail_open_graph_description_program_excerpt( self): """ An opengraph description meta should be present if the program_excerpt placeholder is set. """ program = ProgramFactory() page = program.extended_object # Add a excerpt to a program placeholder = program.extended_object.placeholders.get( slot="program_excerpt") add_plugin( language="en", placeholder=placeholder, plugin_type="PlainTextPlugin", body="A program excerpt description", ) page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains( response, '<meta property="og:description" content="A program excerpt description" />', )
def test_cms_plugins_program_render_on_draft_page(self): """ The program plugin should render as expected on a draft page. """ staff = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=staff.username, password="******") # Create a Program program = ProgramFactory(page_title="public title") program_page = program.extended_object # Create a page to add the plugin to page = create_i18n_page("A page") placeholder = page.placeholders.get(slot="maincontent") add_plugin(placeholder, ProgramPlugin, "en", **{"page": program_page}) program_page.publish("en") program_page.unpublish("en") program_page.refresh_from_db() url = "{:s}?edit".format(page.get_absolute_url(language="en")) # The program plugin should still be visible on the draft page response = self.client.get(url) self.assertContains(response, "public title") # Now modify the program to have a draft different from the public version title_obj = program_page.get_title_obj(language="en") title_obj.title = "draft title" title_obj.save() # The draft version of the program plugin should now be visible response = self.client.get(url) self.assertContains(response, "draft title") self.assertNotContains(response, "public title")
def test_templates_program_detail_meta_description_program_excerpt(self): """ The program meta description should show the program_excerpt if no meta_description is specified """ program = ProgramFactory() page = program.extended_object # Add a excerpt to a program placeholder = program.extended_object.placeholders.get( slot="program_excerpt") add_plugin( language="en", placeholder=placeholder, plugin_type="PlainTextPlugin", body="A program excerpt description", ) page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains( response, '<meta name="description" content="A program excerpt description" />', )
def test_templates_program_detail_cms_draft_content(self): """ A staff user should see a draft program including only its public elements. """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains(response, "<title>Preums</title>", html=True, status_code=200) self.assertContains(response, '<h1 class="subheader__title">Preums</h1>', html=True) # The published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<p class="course-glimpse__title">{:s}</p>'.format( course.extended_object.get_title()), html=True, ) # Draft courses should not be present on the page for course in courses[-2:]: self.assertNotIn( course.extended_object.get_absolute_url(), re.sub(" +", " ", str(response.content).replace("\\n", "")), ) self.assertNotContains( response, course.extended_object.get_title(), html=True, )
def test_templates_program_detail_cms_published_content(self): """ Validate that the important elements are displayed on a published program page """ courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should not be visible before it is published url = page.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 404) # Publish the program and ensure the content is correct page.publish("en") response = self.client.get(url) self.assertContains( response, "<title>Preums - Program - example.com</title>", html=True, status_code=200, ) self.assertContains(response, '<h1 class="subheader__title">Preums</h1>', html=True) # Only published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<span class="course-glimpse__title-text">{0:s}</span>'.format( # noqa pylint: disable=consider-using-f-string,line-too-long course.extended_object.get_title()), html=True, ) for course in courses[-2:]: self.assertNotContains(response, course.extended_object.get_title())
def test_templates_program_list_cms_content(self): """ Validate that the public website only displays programs that are currently published, while staff users can see draft and unpublished programs. """ page = PageFactory( template="courses/cms/program_list.html", title__language="en", should_publish=True, ) ProgramFactory(page_parent=page, page_title="First program") ProgramFactory( page_parent=page, page_title="Second program", should_publish=True ) # Publish with a publication date in the future future = timezone.now() + timedelta(hours=1) with mock.patch("cms.models.pagemodel.now", return_value=future): ProgramFactory( page_parent=page, page_title="Third program", should_publish=True ) # Anonymous users should only see published programs response = self.client.get(page.get_absolute_url()) self.assertEqual(response.status_code, 200) self.assertNotContains(response, "First") self.assertContains(response, "Second") self.assertNotContains(response, "Third") # Staff users can see draft and unpublished programs user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") response = self.client.get(page.get_absolute_url()) self.assertEqual(response.status_code, 200) for title in ["First", "Second", "Third"]: self.assertContains(response, title)
def test_cms_plugins_program_fallback_when_never_published(self): """ The program plugin should render in the fallback language when the program page has never been published in the current language. """ # Create a program program = ProgramFactory( page_title={ "en": "public program", "fr": "programme publique" }, fill_cover={ "original_filename": "cover.jpg", "default_alt_text": "my cover", }, ) program_page = program.extended_object # Create a page to add the plugin to page = create_i18n_page({"en": "A page", "fr": "Une page"}) placeholder = page.placeholders.get(slot="maincontent") add_plugin(placeholder, ProgramPlugin, "en", **{"page": program_page}) add_plugin(placeholder, ProgramPlugin, "fr", **{"page": program_page}) # Publish only the French version of the program program_page.publish("fr") # Check the page content in English page.publish("en") url = page.get_absolute_url(language="en") response = self.client.get(url) # Program's name should be present as a link to the cms page self.assertContains( response, '<a href="/en/programme-publique/" class="program-glimpse program-glimpse--link" >', status_code=200, ) # The program's full name should be wrapped in a h2 self.assertContains( response, '<p class="program-glimpse__title">programme publique</p>', html=True, ) self.assertNotContains(response, "public program") # Program's cover should be present pattern = ( r'<div class="program-glimpse__media">' r'<img src="/media/filer_public_thumbnails/filer_public/.*cover\.jpg__300x170' r'.*alt=""') self.assertIsNotNone(re.search(pattern, str(response.content)))
def test_cms_plugins_program_fallback_when_never_published(self): """ The program plugin should render in the fallback language when the program page has never been published in the current language. """ # Create a program program = ProgramFactory( page_title={ "en": "public program", "fr": "programme publique" }, fill_cover={ "original_filename": "cover.jpg", "default_alt_text": "my cover", }, ) program_page = program.extended_object # Create a page to add the plugin to page = create_i18n_page({"en": "A page", "fr": "Une page"}) placeholder = page.placeholders.get(slot="maincontent") add_plugin(placeholder, ProgramPlugin, "en", **{"page": program_page}) add_plugin(placeholder, ProgramPlugin, "fr", **{"page": program_page}) # Publish only the French version of the program program_page.publish("fr") # Check the page content in English page.publish("en") url = page.get_absolute_url(language="en") response = self.client.get(url) html = lxml.html.fromstring(response.content) # The program's full name should be wrapped in a link within an h2 title = html.cssselect(".program-glimpse__title")[0] link = title.cssselect(".program-glimpse__link")[0] self.assertEqual(link.text_content().strip(), "programme publique") self.assertNotContains(response, "public program") # Program's cover should be present cover = html.cssselect(".program-glimpse__media")[0] self.assertEqual(cover.get("aria-hidden"), "true") img = cover.cssselect("img")[0] self.assertIsNotNone( re.search( r"/media/filer_public_thumbnails/filer_public/.*cover\.jpg__300x170", img.get("src"), ))
def test_templates_program_detail_meta_description_empty(self): """ The program meta description should not be present if neither the meta_description field on the page, nor the `program_excerpt` placeholder are filled """ program = ProgramFactory() page = program.extended_object page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertNotContains( response, '<meta name="description"', )
def test_factories_program_body(self): """ ProgramFactory should be able to generate plugins with a realistic body for several languages. """ program = ProgramFactory(page_languages=["fr", "en"], fill_body=True) # Check that the body plugins were created as expected body = program.extended_object.placeholders.get(slot="program_body") self.assertEqual(body.cmsplugin_set.count(), 2) # The body plugins should contain paragraphs for language in ["fr", "en"]: description_plugin = body.cmsplugin_set.get( plugin_type="TextPlugin", language=language) self.assertIn("<p>", description_plugin.djangocms_text_ckeditor_text.body)
def test_factories_program_excerpt(self): """ ProgramFactory should be able to generate plugins with a realistic excerpt for several languages. """ program = ProgramFactory(page_languages=["fr", "en"], fill_excerpt=True) # Check that the excerpt plugins were created as expected excerpt = program.extended_object.placeholders.get( slot="program_excerpt") self.assertEqual(excerpt.cmsplugin_set.count(), 2) # The excerpt plugins should contain paragraphs for language in ["fr", "en"]: excerpt_plugin = excerpt.cmsplugin_set.get( plugin_type="PlainTextPlugin", language=language) self.assertTrue(len(excerpt_plugin.plain_text_plaintext.body) > 0)
def test_templates_program_detail_meta_description_empty_program_excerpt( self): """ The opengraph description meta should be missing if the program_excerpt placeholder is not set. """ program = ProgramFactory() page = program.extended_object page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertNotContains( response, "og:description", )
def test_factories_program_cover(self): """ ProgramFactory should be able to generate plugins with a realistic cover for several languages. """ program = ProgramFactory(page_languages=["fr", "en"], fill_cover=True) # Check that the cover plugins were created as expected cover = program.extended_object.placeholders.get(slot="program_cover") self.assertEqual(cover.cmsplugin_set.count(), 2) # The cover plugins should point to one of our fixtures images for language in ["fr", "en"]: cover_plugin = cover.cmsplugin_set.get( plugin_type="SimplePicturePlugin", language=language) self.assertIn( "cover", os.path.basename( cover_plugin.djangocms_picture_picture.picture.file.name), )
def test_cms_plugins_program_form_page_choices(self): """ The form to create a program plugin should only list program pages in the select box. """ class ProgramPluginModelForm(forms.ModelForm): """A form for testing the choices in the select box""" class Meta: model = ProgramPluginModel fields = ["page"] program_page = create_i18n_page("my title", published=True) program = ProgramFactory(page_parent=program_page) other_page_title = "other page" create_page(other_page_title, "richie/single_column.html", settings.LANGUAGE_CODE) plugin_form = ProgramPluginModelForm() rendered_form = plugin_form.as_table() self.assertEqual( rendered_form.count(program.extended_object.get_title()), 1) self.assertNotIn(other_page_title, plugin_form.as_table())
def test_templates_program_detail_meta_description(self): """ The program meta description should show meta_description placeholder if defined """ program = ProgramFactory() page = program.extended_object title_obj = page.get_title_obj(language="en") title_obj.meta_description = "A custom description of the program" title_obj.save() page.publish("en") url = program.extended_object.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains( response, '<meta name="description" content="A custom description of the program" />', )
def test_cms_plugins_program_render_on_public_page(self): """ The program plugin should render as expected on a public page. """ # Create an program program = ProgramFactory( page_title={ "en": "public title", "fr": "titre public" }, fill_cover={ "original_filename": "cover.jpg", "default_alt_text": "my cover", }, ) program_page = program.extended_object # Create a page to add the plugin to page = create_i18n_page({"en": "A page", "fr": "Une page"}) placeholder = page.placeholders.get(slot="maincontent") add_plugin(placeholder, ProgramPlugin, "en", **{"page": program_page}) add_plugin(placeholder, ProgramPlugin, "fr", **{"page": program_page}) program_page.publish("en") program_page.publish("fr") program.refresh_from_db() page.publish("en") page.publish("fr") # Check the page content in English url = page.get_absolute_url(language="en") # The program plugin should not be visible on the public page before it is published program_page.unpublish("en") response = self.client.get(url) self.assertNotContains(response, "public title") # # Republish the plugin program_page.publish("en") # Now modify the program to have a draft different from the public version title_obj = program_page.get_title_obj(language="en") title_obj.title = "draft title" title_obj.save() # Publishing the page again should make the plugin public page.publish("en") # Check the page content in English response = self.client.get(url) # The program's name should be present as a link to the cms page self.assertContains( response, '<a href="/en/public-title/" class="program-glimpse program-glimpse--link', status_code=200, ) # The program's title should be wrapped in a p self.assertContains( response, '<p class="program-glimpse__title">{:s}</p>'.format( program.public_extension.extended_object.get_title()), html=True, ) self.assertNotContains(response, "draft title") # Program's cover should be present pattern = ( r'<div class="program-glimpse__media">' r'<img src="/media/filer_public_thumbnails/filer_public/.*cover\.jpg__300x170' r'.*alt=""') self.assertIsNotNone(re.search(pattern, str(response.content))) # Same checks in French url = page.get_absolute_url(language="fr") response = self.client.get(url) self.assertContains( response, '<a href="/fr/titre-public/" class="program-glimpse program-glimpse--link', status_code=200, ) # pylint: disable=no-member pattern = ( r'<div class="program-glimpse__media">' r'<img src="/media/filer_public_thumbnails/filer_public/.*cover\.jpg__300x170' r'.*alt=""') self.assertIsNotNone(re.search(pattern, str(response.content)))
def test_templates_program_detail_cms_draft_content(self): """ A staff user should see a draft program including draft elements. """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[3].extended_object.publish("en") courses[3].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains( response, "<title>Preums - Program - example.com</title>", html=True, status_code=200, ) self.assertContains(response, '<h1 class="subheader__title">Preums</h1>', html=True) # Draft and published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<a class="course-glimpse__link" ' f'href="{course.extended_object.get_absolute_url():s}"', ) self.assertContains( response, '<span class="course-glimpse__title-text">{0:s}</span>'.format( # noqa pylint: disable=consider-using-f-string,line-too-long course.extended_object.get_title()), html=True, ) self.assertContains( response, '<div class="course-glimpse course-glimpse--draft">' '<div aria-hidden="true" class="course-glimpse__media">' f'<a tabindex="-1" href="{courses[2].extended_object.get_absolute_url():s}"', ) self.assertContains( response, '<span class="course-glimpse__title-text">{0:s}</span>'.format( # noqa pylint: disable=consider-using-f-string,line-too-long courses[2].extended_object.get_title()), html=True, ) # The unpublished course should not be present on the page self.assertNotContains(response, courses[3].extended_object.get_title())
def test_templates_program_detail_cms_draft_content(self): """ A staff user should see a draft program including its draft elements with an annotation. """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains( response, "<title>Preums</title>", html=True, status_code=200 ) self.assertContains( response, '<h1 class="program-detail__title">Preums</h1>', html=True ) # The published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<p class="course-glimpse__content__title">{:s}</p>'.format( course.extended_object.get_title() ), html=True, ) # Draft courses should also be present on the page with an annotation for styling for course in courses[-2:]: self.assertContains( response, '<a href="{link:s}" class="{name:s} {name:s}--link {name:s}--draft">'.format( name="course-glimpse", link=course.extended_object.get_absolute_url(), ), ) self.assertContains( response, '<p class="course-glimpse__content__title">{title:s}</p>'.format( title=course.extended_object.get_title() ), html=True, )