def test_models_course_state_coming_soon(self): """ Confirm course state result when there is no course runs at all. """ course = CourseFactory() with self.assertNumQueries(3): state = course.state self.assertEqual(state, CourseState(6))
def test_models_course_state_archived(self): """ Confirm course state when there is a course run only in the past. """ course = CourseFactory() self.create_run_archived(course) with self.assertNumQueries(2): state = course.state self.assertEqual(state, CourseState(5))
def test_templates_course_run_detail_state_with_cta(self): """A course run in a state with a call to action should include a link and the CTA.""" response = self.prepare_to_test_state(CourseState(0, timezone.now())) self.assertContains( response, '<a class="subheader__cta" ' 'href="https://www.example.com/enroll">Enroll now</a>', html=True, )
def test_models_course_state_archived_open(self): """ Confirm course state when there is a past course run but open for enrollment. """ course = CourseFactory() course_run = self.create_run_archived_open(course) with self.assertNumQueries(3): state = course.state self.assertEqual(state, CourseState(2, course_run.enrollment_end))
def test_templates_course_detail_state_with_cta(self): """A course run in a state with a call to action should include a link and the CTA.""" response = self.prepare_to_test_state(CourseState(0, timezone.now())) self.assertContains( response, '<a class="course-detail__aside__run__block__cta" ' 'href="/en/my-course/my-course-run/">Enroll now</a>', html=True, )
def test_templates_course_run_detail_state_without_cta(self): """A course run in a state without a call to action should include a state button.""" response = self.prepare_to_test_state(CourseState(6)) self.assertContains( response, '<button class="subheader__cta ' 'subheader__cta--projected">To be scheduled</button>', html=True, )
def test_templates_course_detail_state_without_cta(self): """A course run in a state without a call to action should include a state button.""" response = self.prepare_to_test_state(CourseState(6)) self.assertContains( response, '<a class="course-detail__aside__run__block__cta ' 'course-detail__aside__run__block__cta--projected" ' 'href="/en/my-course/my-course-run/">To be scheduled</a>', html=True, )
def test_models_course_state_ongoing_enrollment_closed(self): """ Confirm course state when there is an on-going course run but closed for enrollment. """ course = CourseFactory() self.create_run_ongoing_closed(course) with self.assertNumQueries(2): state = course.state self.assertEqual(state, CourseState(4))
def test_models_course_run_state_ongoing_closed(self): """ A course run that is on-going but closed for enrollment should return a state with "on-going" as text and no CTA. """ course_run = CourseRunFactory( enrollment_start=self.now - timedelta(hours=3), start=self.now - timedelta(hours=2), enrollment_end=self.now - timedelta(hours=1), end=self.now + timedelta(hours=1), ) self.assertEqual(course_run.state, CourseState(4, None, "on-going", None))
def test_models_course_run_state_future_closed(self): """ A course run that is future and already closed for enrollment should return a state with "enrollment closed" as text and no CTA. """ course_run = CourseRunFactory( enrollment_start=self.now - timedelta(hours=2), enrollment_end=self.now - timedelta(hours=1), start=self.now + timedelta(hours=1), end=self.now + timedelta(hours=2), ) self.assertEqual( course_run.state, CourseState(3, None, "enrollment closed", None) )
def test_indexers_courses_format_es_object_for_api_no_organization(self): """ A course that has no organization and was indexed should not raise 500 errors (although this should not happen if courses are correctly moderated). """ es_course = { "_id": 93, "_source": { "absolute_url": {"en": "campo-qui-format-do"}, "categories": [43, 86], "code": "abc123", "cover_image": {"en": "cover_image.jpg"}, "duration": {"en": "3 weeks"}, "effort": {"en": "10 minutes"}, "icon": {"en": "icon.jpg"}, "introduction": {"en": "introductio est"}, "organization_highlighted": None, "organization_highlighted_cover_image": {}, "organizations": [], "organizations_names": {}, "title": {"en": "Duis eu arcu erat"}, }, "fields": { "state": [ {"priority": 0, "date_time": "2019-03-17T21:25:52.179667+00:00"} ] }, } self.assertEqual( CoursesIndexer.format_es_object_for_api(es_course, "en"), { "id": 93, "absolute_url": "campo-qui-format-do", "categories": [43, 86], "code": "abc123", "cover_image": "cover_image.jpg", "duration": "3 weeks", "effort": "10 minutes", "icon": "icon.jpg", "introduction": "introductio est", "organization_highlighted": None, "organization_highlighted_cover_image": None, "organizations": [], "title": "Duis eu arcu erat", "state": CourseState( 0, datetime(2019, 3, 17, 21, 25, 52, 179667, pytz.utc) ), }, )
def test_templates_course_run_detail_state_without_cta(self): """A course run in a state without a call to action should include a state button.""" response = self.prepare_to_test_state( CourseState( random.randint(0, 6), None, "state text", random.choice([datetime.now(), None]), )) self.assertContains( response, '<button class="course-detail__content__run__block__cta ' 'course-detail__content__run__block__cta--projected">State text</button>', html=True, )
def test_templates_course_run_detail_state_with_cta(self): """A course run in a state with a call to action should include a link and the CTA.""" response = self.prepare_to_test_state( CourseState( random.randint(0, 6), "state cta", random.choice(["state text", None]), random.choice([datetime.now(), None]), )) self.assertContains( response, '<a class="course-detail__content__run__block__cta" ' 'href="https://www.example.com/enroll">State cta</a>', html=True, )
def test_models_course_run_state_coming(self): """ A course run that is future and not yet open for enrollment should return a state with a CTA to see details with the start date. """ course_run = CourseRunFactory( enrollment_start=self.now + timedelta(hours=1), enrollment_end=self.now + timedelta(hours=2), start=self.now + timedelta(hours=3), end=self.now + timedelta(hours=4), ) self.assertEqual( course_run.state, CourseState(2, "see details", "starting on", course_run.start), )
def test_models_course_run_state_ongoing_open(self): """ A course run that is on-going and open for enrollment should return a state with a CTA to enroll and the date of the end of enrollment. """ course_run = CourseRunFactory( enrollment_start=self.now - timedelta(hours=3), start=self.now - timedelta(hours=2), enrollment_end=self.now + timedelta(hours=1), end=self.now + timedelta(hours=2), ) self.assertEqual( course_run.state, CourseState(0, "enroll now", "closing on", course_run.enrollment_end), )
def test_templates_course_run_detail_state_with_enrollments_app_without_cta( self): """A course run in a state without a call to action just calls the frontend component.""" response, course_run = self.prepare_to_test_state( CourseState(6, timezone.now()), resource_link= "http://edx:8073/courses/course-v1:edX+DemoX+Demo/course/", ) self.assertIsNotNone( re.search( (r'.*class="richie-react richie-react--course-run-enrollment".*' r"data-props=\\\'{{\"courseRunId\": {}}}\\\'".format( course_run.public_extension_id)), str(response.content), ))
def test_models_course_run_state_future_open(self): """ A course run that is future and open for enrollment should return a state with a CTA to enroll and the start date. """ course_run = CourseRunFactory( enrollment_start=self.now - timedelta(hours=1), enrollment_end=self.now + timedelta(hours=1), start=self.now + timedelta(hours=2), end=self.now + timedelta(hours=3), ) self.assertEqual( course_run.state, CourseState(1, "enroll now", "starting on", course_run.start), )
def test_indexers_courses_format_es_object_for_api_no_cover(self): """ A course that has no cover image and was indexed should not raise any errors. """ es_course = { "_id": 93, "_source": { "absolute_url": {"en": "campo-qui-format-do"}, "categories": [43, 86], "code": "abc123", "cover_image": {}, "duration": {"en": "N/A"}, "effort": {"en": "N/A"}, "icon": {"en": "icon.jpg"}, "introduction": {"en": "introductio est"}, "organization_highlighted": {"en": "Org 42"}, "organization_highlighted_cover_image": {}, "organizations": [42, 84], "organizations_names": {"en": ["Org 42", "Org 84"]}, "title": {"en": "Duis eu arcu erat"}, }, "fields": { "state": [ {"priority": 0, "date_time": "2019-03-17T21:25:52.179667+00:00"} ] }, } self.assertEqual( CoursesIndexer.format_es_object_for_api(es_course, "en"), { "id": 93, "absolute_url": "campo-qui-format-do", "categories": [43, 86], "code": "abc123", "cover_image": None, "duration": "N/A", "effort": "N/A", "icon": "icon.jpg", "introduction": "introductio est", "organization_highlighted": "Org 42", "organization_highlighted_cover_image": None, "organizations": [42, 84], "title": "Duis eu arcu erat", "state": CourseState( 0, datetime(2019, 3, 17, 21, 25, 52, 179667, pytz.utc) ), }, )
def test_indexers_courses_format_es_object_for_api(self): """ Make sure format_es_object_for_api returns a properly formatted course """ es_course = { "_id": 93, "_source": { "absolute_url": {"en": "campo-qui-format-do"}, "categories": [43, 86], "code": "abc123", "cover_image": {"en": "cover_image.jpg"}, "duration": {"en": "6 months"}, "effort": {"en": "3 hours"}, "icon": {"en": "icon.jpg"}, "introduction": {"en": "introductio est"}, "organization_highlighted": {"en": "Org 84"}, "organization_highlighted_cover_image": {"en": "org_cover_image.jpg"}, "organizations": [42, 84], "organizations_names": {"en": ["Org 42", "Org 84"]}, "title": {"en": "Duis eu arcu erat"}, }, "fields": { "state": [ {"priority": 0, "date_time": "2019-03-17T21:25:52.179667+00:00"} ] }, } self.assertEqual( CoursesIndexer.format_es_object_for_api(es_course, "en"), { "id": 93, "absolute_url": "campo-qui-format-do", "categories": [43, 86], "code": "abc123", "cover_image": "cover_image.jpg", "duration": "6 months", "effort": "3 hours", "icon": "icon.jpg", "introduction": "introductio est", "organization_highlighted": "Org 84", "organization_highlighted_cover_image": "org_cover_image.jpg", "organizations": [42, 84], "title": "Duis eu arcu erat", "state": CourseState( 0, datetime(2019, 3, 17, 21, 25, 52, 179667, pytz.utc) ), }, )
def test_models_course_state_future_enrollment_closed(self): """ Confirm course state when there is a future course run but closed for enrollment. """ course = CourseFactory() self.create_run_future_closed(course) with self.assertNumQueries(2): state = course.state expected_state = CourseState(3) self.assertEqual(state, expected_state) # Adding an on-going but closed course run should not change the result self.create_run_ongoing_closed(course) with self.assertNumQueries(2): state = course.state self.assertEqual(state, expected_state)
def test_models_course_state_future_enrollment_open(self): """ Confirm course state when there is a future course run open for enrollment. """ course = CourseFactory() course_run = self.create_run_future_open(course) with self.assertNumQueries(2): state = course.state expected_state = CourseState(1, course_run.start) self.assertEqual(state, expected_state) # Adding courses in less priorietary states should not change the result self.create_run_ongoing_closed(course) self.create_run_future_closed(course) with self.assertNumQueries(2): state = course.state self.assertEqual(state, expected_state)
def test_models_course_state_future_enrollment_not_yet_open(self): """ Confirm course state when there is a future course run but not yet open for enrollment. """ course = CourseFactory() course_run = self.create_run_future_not_yet_open(course) with self.assertNumQueries(2): state = course.state expected_state = CourseState(2, course_run.start) self.assertEqual(state, expected_state) # Adding an on-going but closed course run should not change the result and require # only 1 additional database query self.create_run_ongoing_closed(course) with self.assertNumQueries(1): state = course.state self.assertEqual(state, expected_state)
def test_models_course_state_future_enrollment_open(self): """ Confirm course state when there is a future course run open for enrollment. """ course = CourseFactory() course_run = self.create_run_future_open(course) with self.assertNumQueries(3): state = course.state expected_state = CourseState(1, course_run.start) self.assertEqual(state, expected_state) # Adding course runs of lower priority states should not change the result and require # only 1 additional database query self.create_run_ongoing_closed(course) self.create_run_future_closed(course) with self.assertNumQueries(1): state = course.state self.assertEqual(state, expected_state)
def test_models_course_state_ongoing_open(self): """ Confirm course state when there is an on-going course run open for enrollment. """ course = CourseFactory() course_run = CourseRunFactory( page_parent=course.extended_object, start=self.now - timedelta(hours=1), end=self.now + timedelta(hours=2), enrollment_end=self.now + timedelta(hours=1), ) with self.assertNumQueries(2): state = course.state expected_state = CourseState(0, course_run.enrollment_end) self.assertEqual(state, expected_state) # Adding courses in less priorietary states should not change the result self.create_run_ongoing_closed(course) self.create_run_future_closed(course) self.create_run_future_open(course) with self.assertNumQueries(2): state = course.state self.assertEqual(state, expected_state)
def test_models_course_run_state_archived(self): """A course run that is passed should return a state with "archived" as text.""" course_run = CourseRunFactory( start=self.now - timedelta(hours=2), end=self.now - timedelta(hours=1) ) self.assertEqual(course_run.state, CourseState(5, None, "archived", None))