def test_models_category_get_courses_snapshots(self): """ Snapshot courses should be excluded from the list of courses returned. The new filter query we added to exclude snapshots should not create duplicates. Indeed, we had to add a "distinct" clause to the query so this test enforces it. """ # We create a root page because it was responsible for duplicate results when the # distinct clause is not applied. # This is because of the clause "extended_object__node__parent__cms_pages__..." # which is there to exclude snapshots but also acts on the main course page and # checks its parent (so the root page) and the duplicate comes from the fact that # the parent has a draft and a public page... so "cms_pages" has a cardinality of 2 root_page = create_i18n_page("my title", published=True) category = CategoryFactory(should_publish=True) course = CourseFactory( page_parent=root_page, fill_categories=[category], should_publish=True ) CourseFactory( page_parent=course.extended_object, fill_categories=[category], should_publish=True, ) self.assertEqual(Course.objects.count(), 4) self.assertEqual(category.get_courses().count(), 1) self.assertEqual(category.public_extension.get_courses().count(), 1)
def test_models_category_get_courses_ordering(self): """The related courses should be sorted by their position in the pages tree.""" category = CategoryFactory(should_publish=True) course1, course2, course3 = CourseFactory.create_batch( 3, fill_categories=[category], should_publish=True) self.assertEqual(list(category.get_courses()), [course1, course2, course3]) # Move pages in the tree and check that they are returned in the new order course3.extended_object.move_page(course1.extended_object.node, position="left") self.assertEqual(list(category.get_courses()), [course3, course1, course2]) course1.extended_object.move_page(course3.extended_object.node, position="left") self.assertEqual(list(category.get_courses()), [course1, course3, course2])
def test_models_category_get_courses_several_languages(self): """ The courses should not be duplicated if they exist in several languages. """ category = CategoryFactory(should_publish=True) CourseFactory( page_title={"en": "my title", "fr": "mon titre"}, fill_categories=[category], should_publish=True, ) self.assertEqual(Course.objects.count(), 2) self.assertEqual(category.get_courses().count(), 1)
def test_templates_category_detail_cms_published_content_max_courses( self, _mock_page_url): """ Make sure the category detail page does not display too many courses, even when a large number are related to the current category, as this can cause the page to load very slowly and is not a great experience for the user anyway. """ # Create our dummy category and the 3 courses we'll attach to it meta = CategoryFactory( page_parent=create_i18n_page( { "en": "Categories", "fr": "Catégories" }, published=True), page_reverse_id="subjects", page_title={ "en": "Subjects", "fr": "Sujets" }, should_publish=True, ) category = CategoryFactory(page_parent=meta.extended_object, should_publish=True) courses = CourseFactory.create_batch(3, fill_categories=[category], should_publish=True) # Link the 3 courses with our category through the relevant placeholder for course in courses: add_plugin( course.extended_object.placeholders.get( slot="course_categories"), CategoryPlugin, "en", page=category.extended_object, ) # Make sure we do have 3 courses on the category self.assertEqual(category.get_courses().count(), 3) # Only the first two are rendered in the template response = self.client.get(category.extended_object.get_absolute_url()) self.assertContains(response, courses[0].extended_object.get_title()) self.assertContains(response, courses[1].extended_object.get_title()) self.assertNotContains(response, courses[2].extended_object.get_title()) # There is a link to view more related courses directly in the Search view self.assertContains( response, f'href="/the/courses/?subjects={category.get_es_id():s}"') self.assertContains( response, f"See all courses related to {category.extended_object.get_title():s}", )
def test_templates_category_detail_cms_published_content_max_courses_on_meta( self, _mock_page_url): """ Meta categories are a special case: technically, any page linked to one of their children is linked to the meta-category too. This means in a lot of cases we just want a link to *all* courses not just their related courses. The Search view is also not equipped to filter on a meta-category. In this case, we just link to it with a different link text. """ # Create our dummy category and the 3 courses we'll attach to it meta = CategoryFactory( page_parent=create_i18n_page( { "en": "Categories", "fr": "Catégories" }, published=True), page_reverse_id="subjects", page_title={ "en": "Subjects", "fr": "Sujets" }, should_publish=True, ) category = CategoryFactory(page_parent=meta.extended_object, should_publish=True) courses = CourseFactory.create_batch(3, fill_categories=[category], should_publish=True) # Link the 3 courses with our category through the relevant placeholder for course in courses: add_plugin( course.extended_object.placeholders.get( slot="course_categories"), CategoryPlugin, "en", page=category.extended_object, ) # Make sure we do have 3 courses on the category self.assertEqual(category.get_courses().count(), 3) # NB: here we are requesting the meta category's page, not the child category # Only the first two are rendered in the template response = self.client.get(meta.extended_object.get_absolute_url()) self.assertContains(response, courses[0].extended_object.get_title()) self.assertContains(response, courses[1].extended_object.get_title()) self.assertNotContains(response, courses[2].extended_object.get_title()) # There is a link to view all courses self.assertContains(response, 'href="/the/courses/') self.assertContains(response, "See all courses")
def test_models_category_get_courses_descendants(self): """ Related courses should include the courses linked to the category's descendants, unless specifically deactivated by the "include_descendants" argument. """ category_page = create_page("Subjects", "courses/cms/category_detail.html", "en", published=True) category = CategoryFactory(extended_object=category_page, should_publish=True) courses = CourseFactory.create_batch(2, fill_categories=[category], should_publish=True) child_category_page = create_page( "Literature", "courses/cms/category_detail.html", "en", parent=category_page, published=True, ) child_category = CategoryFactory(extended_object=child_category_page, should_publish=True) courses_child = CourseFactory.create_batch( 2, fill_categories=[child_category], should_publish=True) grand_child_category_page = create_page( "Literature", "courses/cms/category_detail.html", "en", parent=child_category_page, published=True, ) grand_child_category = CategoryFactory( extended_object=grand_child_category_page, should_publish=True) courses_grand_child = CourseFactory.create_batch( 2, fill_categories=[grand_child_category], should_publish=True) # Check that each category gets courses from its descendants # ...unless we pass an argument to deactivate it self.assertEqual(list(category.get_courses()), courses + courses_child + courses_grand_child) self.assertEqual(list(category.get_courses(include_descendants=False)), courses) self.assertEqual(list(child_category.get_courses()), courses_child + courses_grand_child) self.assertEqual( list(child_category.get_courses(include_descendants=False)), courses_child) self.assertEqual( list(grand_child_category.get_courses(include_descendants=False)), courses_grand_child, ) self.assertEqual(list(grand_child_category.get_courses()), courses_grand_child)
def test_models_category_get_courses(self): """ It should be possible to retrieve the list of related courses on the category instance. The number of queries should be minimal. """ category = CategoryFactory(should_publish=True) courses = CourseFactory.create_batch( 3, page_title="my title", fill_categories=[category], should_publish=True ) retrieved_courses = category.get_courses() with self.assertNumQueries(2): self.assertEqual(set(retrieved_courses), set(courses)) with self.assertNumQueries(0): for course in retrieved_courses: self.assertEqual( course.extended_object.prefetched_titles[0].title, "my title" )
def test_models_category_get_courses_public_category_page(self): """ When a category is added on a draft course, the course should not be visible on the public category page until the course is published. """ category = CategoryFactory(should_publish=True) category_page = category.extended_object course = CourseFactory(page_title="my title", should_publish=True) course_page = course.extended_object # Add a category to the course but don't publish the modification placeholder = course_page.placeholders.get(slot="course_categories") add_plugin(placeholder, CategoryPlugin, "en", page=category_page) self.assertEqual(list(category.get_courses()), [course]) self.assertEqual(list(category.public_extension.get_courses()), []) # Now publish the modification and check that the course is displayed # on the public category page course.extended_object.publish("en") self.assertEqual(list(category.public_extension.get_courses()), [course.public_extension])