def test_certificate_footer_data(self): """ Test that get_certificate_footer_context from certificates api returns data customized according to site branding. """ # Generate certificates for the course CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug=CourseMode.HONOR) data = certs_api.get_certificate_footer_context() # Make sure there are not unexpected keys in dict returned by 'get_certificate_footer_context' self.assertItemsEqual( data.keys(), ['company_about_url', 'company_privacy_url', 'company_tos_url'] ) # ABOUT is present in MICROSITE_CONFIGURATION['test_microsite']["urls"] so web certificate will use that url self.assertIn( settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['ABOUT'], data['company_about_url'] ) # PRIVACY is present in MICROSITE_CONFIGURATION['test_microsite']["urls"] so web certificate will use that url self.assertIn( settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['PRIVACY'], data['company_privacy_url'] ) # TOS_AND_HONOR is present in MICROSITE_CONFIGURATION['test_microsite']["urls"], # so web certificate will use that url self.assertIn( settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['TOS_AND_HONOR'], data['company_tos_url'] )
def test_access_denied_fragment_for_masquerading(self): """ Test that a global staff sees gated content flag when viewing course as `Learner in Limited Access` Note: Global staff doesn't require to be enrolled in course. """ mock_request = RequestFactory().get('/') mock_course = Mock(id=self.course_key, user_partitions={}) mock_block = Mock(scope_ids=Mock(usage_id=Mock(course_key=mock_course.id))) mock_course_masquerade = Mock( role='student', user_partition_id=CONTENT_GATING_PARTITION_ID, group_id=LIMITED_ACCESS.id, user_name=None ) CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified') global_staff = GlobalStaffFactory.create() ContentTypeGatingConfig.objects.create(enabled=False, studio_override_enabled=True) partition = create_content_gating_partition(mock_course) with patch( 'crum.get_current_request', return_value=mock_request ): fragment = partition.access_denied_fragment(mock_block, global_staff, LIMITED_ACCESS, [FULL_ACCESS]) self.assertIsNotNone(fragment)
def test_professional_enrollment(self, mode): # The only course mode is professional ed CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=1) # Go to the "choose your track" page choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(choose_track_url) # Since the only available track is professional ed, expect that # we're redirected immediately to the start of the payment flow. purchase_workflow = "?purchase_workflow=single" start_flow_url = reverse('verify_student_start_flow', args=[unicode(self.course.id)]) + purchase_workflow self.assertRedirects(response, start_flow_url) # Now enroll in the course CourseEnrollmentFactory( user=self.user, is_active=True, mode=mode, course_id=unicode(self.course.id), ) # Expect that this time we're redirected to the dashboard (since we're already registered) response = self.client.get(choose_track_url) self.assertRedirects(response, reverse('dashboard'))
def test_enterprise_learner_context(self): """ Test: Track selection page should show the enterprise context message if user belongs to the Enterprise. """ # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) self.mock_enterprise_learner_api() self.mock_course_discovery_api_for_catalog_contains( catalog_id=1, course_run_ids=[str(self.course.id)] ) # User visits the track selection page directly without ever enrolling url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) self.assertEquals(response.status_code, 200) self.assertContains( response, 'Welcome, {username}! You are about to enroll in {course_name}, from {partner_names}, ' 'sponsored by TestShib. Please select your enrollment information below.'.format( username=self.user.username, course_name=self.course.display_name_with_default_escaped, partner_names=self.course.org ) )
def test_access_denied_fragment_for_masquerading(self): """ Test that a global staff sees gated content flag when viewing course as `Learner in Audit` Note: Global staff doesn't require to be enrolled in course. """ mock_request = RequestFactory().get('/') mock_course = Mock(id=self.course_key, user_partitions={}) mock_block = Mock(scope_ids=Mock(usage_id=Mock(course_key=mock_course.id))) mock_course_masquerade = Mock( role='student', user_partition_id=ENROLLMENT_TRACK_PARTITION_ID, group_id=settings.COURSE_ENROLLMENT_MODES['audit']['id'], user_name=None ) CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified') global_staff = GlobalStaffFactory.create() ContentTypeGatingConfig.objects.create(enabled=False, studio_override_enabled=True) partition = create_content_gating_partition(mock_course) with patch( 'courseware.masquerade.get_course_masquerade', return_value=mock_course_masquerade ), patch( 'openedx.features.content_type_gating.partitions.get_course_masquerade', return_value=mock_course_masquerade ), patch( 'crum.get_current_request', return_value=mock_request ): fragment = partition.access_denied_fragment(mock_block, global_staff, GroupFactory(), 'test_allowed_group') self.assertIsNotNone(fragment)
def test_missing_enrollment_mode(self): """ Test that an enrollment mode that is no longer registered is displayed as 'deleted', regardless of the number of current enrollment modes in the course. """ # Only 1 mode (the default) exists, so nothing initially shows in the visibility view. self.verify_visibility_view_contains( self.video_location, [self.NO_CONTENT_OR_ENROLLMENT_GROUPS, self.NO_CONTENT_ENROLLMENT_TRACK_ENABLED] ) self.verify_visibility_view_does_not_contain( self.video_location, [self.ENROLLMENT_GROUPS_TITLE, self.GROUP_NO_LONGER_EXISTS] ) # Set group_access to reference a missing mode. self.set_group_access(self.video_location, ['10'], ENROLLMENT_TRACK_PARTITION_ID) self.verify_visibility_view_contains( self.video_location, [self.ENROLLMENT_GROUPS_TITLE, self.GROUP_NO_LONGER_EXISTS] ) # Add 2 explicit enrollment modes. CourseModeFactory.create(course_id=self.course.id, mode_slug='audit') CourseModeFactory.create(course_id=self.course.id, mode_slug='verified') self.verify_visibility_view_contains( self.video_location, [self.ENROLLMENT_GROUPS_TITLE, 'audit course', 'verified course', self.GROUP_NO_LONGER_EXISTS] )
def setup_course_and_user( self, days_till_start=1, days_till_end=14, days_till_upgrade_deadline=4, enrollment_mode=CourseMode.VERIFIED, days_till_verification_deadline=14, verification_status=None, ): """Set up the course and user for this test.""" now = datetime.now(pytz.UTC) self.course = CourseFactory.create( # pylint: disable=attribute-defined-outside-init start=now + timedelta(days=days_till_start), end=now + timedelta(days=days_till_end), ) self.user = UserFactory.create() # pylint: disable=attribute-defined-outside-init if enrollment_mode is not None and days_till_upgrade_deadline is not None: CourseModeFactory.create( course_id=self.course.id, mode_slug=enrollment_mode, expiration_datetime=now + timedelta(days=days_till_upgrade_deadline) ) CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user, mode=enrollment_mode) else: CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user) if days_till_verification_deadline is not None: VerificationDeadline.objects.create( course_key=self.course.id, deadline=now + timedelta(days=days_till_verification_deadline) ) if verification_status is not None: SoftwareSecurePhotoVerificationFactory.create(user=self.user, status=verification_status)
def test_choose_mode_audit_enroll_on_get(self): """ Confirms that the learner will be enrolled in Audit track if it is the only possible option """ self.mock_enterprise_learner_api() self.mock_enterprise_course_enrollment_get_api() # Create the course mode audit_mode = 'audit' CourseModeFactory.create(mode_slug=audit_mode, course_id=self.course.id, min_price=0) # Assert learner is not enrolled in Audit track pre-POST mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertIsNone(mode) self.assertIsNone(is_active) # Choose the audit mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(choose_track_url) # Assert learner is enrolled in Audit track and sent to the dashboard mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertEquals(mode, audit_mode) self.assertTrue(is_active) redirect_url = reverse('dashboard') self.assertRedirects(response, redirect_url)
def test_redirect_to_dashboard(self, is_active, enrollment_mode, redirect): # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) # Enroll the user in the test course if enrollment_mode is not None: CourseEnrollmentFactory( is_active=is_active, mode=enrollment_mode, course_id=self.course.id, user=self.user ) self.mock_enterprise_learner_api() # Configure whether we're upgrading or not url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) # Check whether we were correctly redirected if redirect: self.assertRedirects(response, reverse('dashboard')) else: self.assertEquals(response.status_code, 200)
def test_expired_course_in_holdback(self): """ Ensure that a user accessing an expired course that is in the holdback does not get redirected to the student dashboard, not a 404. """ CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2010, 1, 1)) course = CourseFactory.create(start=THREE_YEARS_AGO) url = course_home_url(course) for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]: CourseModeFactory.create(course_id=course.id, mode_slug=mode) ExperimentKeyValue.objects.create( experiment_id=EXPERIMENT_ID, key="content_type_gating_holdback_percentage", value="100" ) # assert that an if an expired audit user in the holdback tries to access the course # they are not redirected to the dashboard audit_user = UserFactory(password=self.TEST_PASSWORD) self.client.login(username=audit_user.username, password=self.TEST_PASSWORD) audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT) ScheduleFactory(start=THREE_YEARS_AGO, enrollment=audit_enrollment) response = self.client.get(url) self.assertEqual(response.status_code, 200)
def test_transform_with_content_gating_partition(self): self.setup_partitions_and_course() CourseModeFactory.create(course_id=self.course.id, mode_slug='audit') CourseModeFactory.create(course_id=self.course.id, mode_slug='verified') ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1)) partition = create_content_gating_partition(self.course) self.user_partitions.append(partition) cohort = self.partition_cohorts[0][1] add_user_to_cohort(cohort, self.user.username) with patch( 'lms.djangoapps.course_blocks.transformers.user_partitions.get_partition_from_id', return_value=partition ), patch( 'lms.djangoapps.course_blocks.transformers.user_partitions._MergedGroupAccess.get_allowed_groups', return_value={51: set([])} ): trans_block_structure = get_course_blocks( self.user, self.course.location, self.transformers, ) xblocks_denial_reason = [trans_block_structure.get_xblock_field(b, 'authorization_denial_reason') for b in trans_block_structure.get_block_keys()] self.assertSetEqual(set(xblocks_denial_reason), set([u'Feature-based Enrollments']))
def setUp(self): super(TestProfEdVerification, self).setUp() self.user = UserFactory.create(username="******", password="******") self.client.login(username="******", password="******") course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course_key = course.id CourseModeFactory.create( mode_slug="professional", course_id=self.course_key, min_price=self.MIN_PRICE, suggested_prices='' ) purchase_workflow = "?purchase_workflow=single" self.urls = { 'course_modes_choose': reverse( 'course_modes_choose', args=[unicode(self.course_key)] ), 'verify_student_start_flow': reverse( 'verify_student_start_flow', args=[unicode(self.course_key)] ) + purchase_workflow, }
def test_certificate_footer_data(self): """ Test that get_certificate_footer_context from lms.djangoapps.certificates api returns data customized according to site branding. """ # Generate certificates for the course CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug=CourseMode.HONOR) data = certs_api.get_certificate_footer_context() # Make sure there are not unexpected keys in dict returned by 'get_certificate_footer_context' self.assertItemsEqual( data.keys(), ['company_about_url', 'company_privacy_url', 'company_tos_url'] ) self.assertIn( self.configuration['urls']['ABOUT'], data['company_about_url'] ) self.assertIn( self.configuration['urls']['PRIVACY'], data['company_privacy_url'] ) self.assertIn( self.configuration['urls']['TOS_AND_HONOR'], data['company_tos_url'] )
def test_suggested_prices(self, price_list): # Create the course modes for mode in ('audit', 'honor'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create( mode_slug='verified', course_id=self.course.id, suggested_prices=price_list ) # Enroll the user in the test course to emulate # automatic enrollment CourseEnrollmentFactory( is_active=True, course_id=self.course.id, user=self.user ) self.mock_enterprise_learner_api() # Verify that the prices render correctly response = self.client.get( reverse('course_modes_choose', args=[unicode(self.course.id)]), follow=False, ) self.assertEquals(response.status_code, 200)
def _create_course(self): course = CourseFactory.create(run='test', display_name='test') CourseModeFactory.create(course_id=course.id, mode_slug='audit') CourseModeFactory.create(course_id=course.id, mode_slug='verified') blocks_dict = {} with self.store.bulk_operations(course.id): blocks_dict['chapter'] = ItemFactory.create( parent=course, category='chapter', display_name='Week 1' ) blocks_dict['sequential'] = ItemFactory.create( parent=blocks_dict['chapter'], category='sequential', display_name='Lesson 1' ) blocks_dict['vertical'] = ItemFactory.create( parent=blocks_dict['sequential'], category='vertical', display_name='Lesson 1 Vertical - Unit 1' ) return { 'course': course, 'blocks': blocks_dict, }
def test_choose_mode_audit_enroll_on_post(self): audit_mode = 'audit' # Create the course modes for mode in (audit_mode, 'verified'): min_price = 0 if mode in [audit_mode] else 1 CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price) # Assert learner is not enrolled in Audit track pre-POST mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertIsNone(mode) self.assertIsNone(is_active) # Choose the audit mode (POST request) choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[audit_mode]) # Assert learner is enrolled in Audit track post-POST mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertEqual(mode, audit_mode) self.assertTrue(is_active) # Unenroll learner from Audit track and confirm the enrollment record is now 'inactive' CourseEnrollment.unenroll(self.user, self.course.id) mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertEqual(mode, audit_mode) self.assertFalse(is_active) # Choose the audit mode again self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[audit_mode]) # Assert learner is again enrolled in Audit track post-POST-POST mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertEqual(mode, audit_mode) self.assertTrue(is_active)
def test_unpublished_sessions_for_entitlement_when_enrolled(self, mock_get_edx_api_data): """ Test unpublished course runs are part of visible session entitlements when the user is enrolled. """ catalog_course_run = CourseRunFactory.create(status=COURSE_UNPUBLISHED) catalog_course = CourseFactory(course_runs=[catalog_course_run]) mock_get_edx_api_data.return_value = catalog_course course_key = CourseKey.from_string(catalog_course_run.get('key')) course_overview = CourseOverviewFactory.create(id=course_key, start=self.tomorrow) CourseModeFactory.create( mode_slug=CourseMode.VERIFIED, min_price=100, course_id=course_overview.id, expiration_datetime=now() - timedelta(days=1) ) course_enrollment = CourseEnrollmentFactory( user=self.user, course_id=unicode(course_overview.id), mode=CourseMode.VERIFIED ) entitlement = CourseEntitlementFactory( user=self.user, enrollment_course_run=course_enrollment, mode=CourseMode.VERIFIED ) session_entitlements = get_visible_sessions_for_entitlement(entitlement) self.assertEqual(session_entitlements, [catalog_course_run])
def test_expired_course(self): """ Ensure that a user accessing an expired course sees a redirect to the student dashboard, not a 404. """ CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2010, 1, 1)) course = CourseFactory.create(start=THREE_YEARS_AGO) url = course_home_url(course) for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]: CourseModeFactory.create(course_id=course.id, mode_slug=mode) # assert that an if an expired audit user tries to access the course they are redirected to the dashboard audit_user = UserFactory(password=self.TEST_PASSWORD) self.client.login(username=audit_user.username, password=self.TEST_PASSWORD) audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT) ScheduleFactory(start=THREE_YEARS_AGO, enrollment=audit_enrollment) response = self.client.get(url) expiration_date = strftime_localized(course.start + timedelta(weeks=4), 'SHORT_DATE') expected_params = QueryDict(mutable=True) course_name = CourseOverview.get_from_id(course.id).display_name_with_default expected_params['access_response_error'] = 'Access to {run} expired on {expiration_date}'.format( run=course_name, expiration_date=expiration_date ) expected_url = '{url}?{params}'.format( url=reverse('dashboard'), params=expected_params.urlencode() ) self.assertRedirects(response, expected_url)
def test_redirect_to_dashboard(self, is_active, enrollment_mode, redirect, has_started): # Configure whether course has started # If it has go to course home instead of dashboard course = self.course_that_started if has_started else self.course # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory.create(mode_slug=mode, course_id=course.id) # Enroll the user in the test course if enrollment_mode is not None: CourseEnrollmentFactory( is_active=is_active, mode=enrollment_mode, course_id=course.id, user=self.user ) # Configure whether we're upgrading or not url = reverse('course_modes_choose', args=[six.text_type(course.id)]) response = self.client.get(url) # Check whether we were correctly redirected if redirect: if has_started: self.assertRedirects( response, reverse('openedx.course_experience.course_home', kwargs={'course_id': course.id}) ) else: self.assertRedirects(response, reverse('dashboard')) else: self.assertEquals(response.status_code, 200)
def test_score_recalculation_on_enrollment_update(self): """ Test that an update in enrollment cause score recalculation. Note: Score recalculation task must be called with a delay of SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE """ course_modes = ['verified', 'audit'] for mode_slug in course_modes: CourseModeFactory.create( course_id=self.course.id, mode_slug=mode_slug, mode_display_name=mode_slug, ) CourseEnrollment.enroll(self.user, self.course.id, mode="audit") local_task_args = dict( user_id=self.user.id, course_key=str(self.course.id) ) with patch( 'lms.djangoapps.grades.tasks.recalculate_course_and_subsection_grades_for_user.apply_async', return_value=None ) as mock_task_apply: CourseEnrollment.enroll(self.user, self.course.id, mode="verified") mock_task_apply.assert_called_once_with( countdown=SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE, kwargs=local_task_args )
def test_acess_denied_fragment_for_null_request(self): """ Verifies the access denied fragment is visible when HTTP request is not available. Given the HTTP request instance is None Then set the mobile_app context variable to False And the fragment should be created successfully """ mock_request = None mock_course = Mock(id=self.course_key, user_partitions={}) mock_block = Mock(scope_ids=Mock(usage_id=Mock(course_key=mock_course.id))) CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified') global_staff = GlobalStaffFactory.create() ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1)) partition = create_content_gating_partition(mock_course) with patch( 'crum.get_current_request', return_value=mock_request ), patch( 'openedx.features.content_type_gating.partitions.ContentTypeGatingPartition._is_audit_enrollment', return_value=True ): fragment = partition.access_denied_fragment(mock_block, global_staff, GroupFactory(), 'test_allowed_group') self.assertIsNotNone(fragment)
def test_enroll(self, course_modes, next_url, enrollment_mode): # Create the course modes (if any) required for this test case for mode_slug in course_modes: CourseModeFactory.create( course_id=self.course.id, mode_slug=mode_slug, mode_display_name=mode_slug, ) # Reverse the expected next URL, if one is provided # (otherwise, use an empty string, which the JavaScript client # interprets as a redirect to the dashboard) full_url = ( reverse(next_url, kwargs={'course_id': unicode(self.course.id)}) if next_url else next_url ) # Enroll in the course and verify the URL we get sent to resp = self._change_enrollment('enroll') self.assertEqual(resp.status_code, 200) self.assertEqual(resp.content, full_url) # If we're not expecting to be enrolled, verify that this is the case if enrollment_mode is None: self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id)) # Otherwise, verify that we're enrolled with the expected course mode else: self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id)) course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertTrue(is_active) self.assertEqual(course_mode, enrollment_mode)
def test_linked_in_add_to_profile_btn_not_appearing_without_config(self): # Without linked-in config don't show Add Certificate to LinkedIn button self.client.login(username="******", password="******") CourseModeFactory.create( course_id=self.course.id, mode_slug='verified', mode_display_name='verified', expiration_datetime=datetime.now(pytz.UTC) - timedelta(days=1) ) CourseEnrollment.enroll(self.user, self.course.id, mode='honor') self.course.start = datetime.now(pytz.UTC) - timedelta(days=2) self.course.end = datetime.now(pytz.UTC) - timedelta(days=1) self.course.display_name = u"Omega" self.course = self.update_course(self.course, self.user.id) download_url = 'www.edx.org' GeneratedCertificateFactory.create( user=self.user, course_id=self.course.id, status=CertificateStatuses.downloadable, mode='honor', grade='67', download_url=download_url ) response = self.client.get(reverse('dashboard')) self.assertEquals(response.status_code, 200) self.assertNotIn('Add Certificate to LinkedIn', response.content) response_url = 'http://www.linkedin.com/profile/add?_ed=' self.assertNotContains(response, escape(response_url))
def setUp(self): super(ChangeEnrollmentTests, self).setUp() self.course = CourseFactory.create() self.audit_mode = CourseModeFactory.create( course_id=self.course.id, mode_slug='audit', mode_display_name='Audit', ) self.honor_mode = CourseModeFactory.create( course_id=self.course.id, mode_slug='honor', mode_display_name='Honor', ) self.user_info = [ ('amy', '*****@*****.**', 'password'), ('rory', '*****@*****.**', 'password'), ('river', '*****@*****.**', 'password') ] self.enrollments = [] self.users = [] for username, email, password in self.user_info: user = UserFactory.create(username=username, email=email, password=password) self.users.append(user) self.enrollments.append(CourseEnrollment.enroll(user, self.course.id, mode='audit'))
def _create_course(cls, run, display_name, modes, component_types): """ Helper method to create a course Arguments: run (str): name of course run display_name (str): display name of course modes (list of str): list of modes/tracks this course should have component_types (list of str): list of problem types this course should have Returns: (dict): { 'course': (CourseDescriptorWithMixins): course definition 'blocks': (dict) { 'block_category_1': XBlock representing that block, 'block_category_2': XBlock representing that block, .... } """ start_date = timezone.now() - timedelta(weeks=1) course = CourseFactory.create(run=run, display_name=display_name, start=start_date) for mode in modes: CourseModeFactory.create(course_id=course.id, mode_slug=mode) with cls.store.bulk_operations(course.id): blocks_dict = {} chapter = ItemFactory.create( parent=course, display_name='Overview', ) blocks_dict['chapter'] = ItemFactory.create( parent=course, category='chapter', display_name='Week 1', ) blocks_dict['sequential'] = ItemFactory.create( parent=chapter, category='sequential', display_name='Lesson 1', ) blocks_dict['vertical'] = ItemFactory.create( parent=blocks_dict['sequential'], category='vertical', display_name='Lesson 1 Vertical - Unit 1', ) for component_type in component_types: block = ItemFactory.create( parent=blocks_dict['vertical'], category=component_type, display_name=component_type, graded=True, metadata={} if (component_type == 'html' or len(modes) == 1) else METADATA ) blocks_dict[component_type] = block return { 'course': course, 'blocks': blocks_dict, }
def setUp(self): super(DashboardTestsWithSiteOverrides, self).setUp() self.org = 'fakeX' self.course = CourseFactory.create(org=self.org) self.user = UserFactory.create(username='******', email='*****@*****.**', password='******') CourseModeFactory.create(mode_slug='no-id-professional', course_id=self.course.id) CourseEnrollment.enroll(self.user, self.course.location.course_key, mode='no-id-professional') cache.clear()
def add_to_cart(self): """ Adds content to self.user's cart """ course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course') CourseModeFactory.create(course_id=course.id) cart = Order.get_cart_for_user(self.user) PaidCourseRegistration.add_to_order(cart, course.id)
def _create_course_modes(self, course_modes, course=None): """Create the course modes required for a test. """ course_id = course.id if course else self.course.id for mode_slug in course_modes: CourseModeFactory.create( course_id=course_id, mode_slug=mode_slug, mode_display_name=mode_slug, )
def test_unsupported_enrollment_mode_failure(self): # Create the supported course modes for mode in ('honor', 'verified'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) # Choose an unsupported mode (POST request) choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['unsupported']) self.assertEqual(400, response.status_code)
def _enrollment_with_complete_course(self, enrollment_mode): """"Dry method for course enrollment.""" CourseModeFactory.create( course_id=self.course.id, mode_slug='verified', mode_display_name='Verified', expiration_datetime=datetime.now(pytz.UTC) + timedelta(days=1) ) enrollment = CourseEnrollment.enroll(self.user, self.course.id, mode=enrollment_mode) return complete_course_mode_info(self.course.id, enrollment)
def setUp(self): super(TestProfEdVerification, self).setUp() self.user = UserFactory.create(username="******", password="******") self.client.login(username="******", password="******") course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course_key = course.id CourseModeFactory.create(mode_slug="professional", course_id=self.course_key, min_price=self.MIN_PRICE, suggested_prices='') purchase_workflow = "?purchase_workflow=single" self.urls = { 'course_modes_choose': reverse('course_modes_choose', args=[six.text_type(self.course_key)]), 'verify_student_start_flow': reverse('verify_student_start_flow', args=[six.text_type(self.course_key)]) + purchase_workflow, }
def test_credit_upsell_message(self, available_modes, show_upsell): # Create the course modes for mode in available_modes: CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) self.mock_enterprise_learner_api() # Create a service user and log in. UserFactory.create( username='******', email="*****@*****.**", password="******", ) # Check whether credit upsell is shown on the page # This should *only* be shown when a credit mode is available url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) if show_upsell: self.assertContains(response, "Credit") else: self.assertNotContains(response, "Credit")
def test_donate_button_honor_with_price(self): # Enable the enrollment success message and donations self._configure_message_timeout(10000) DonationConfiguration(enabled=True).save() # Create a white-label course mode # (honor mode with a price set) CourseModeFactory(mode_slug="honor", course_id=self.course.id, min_price=100) # Check that the donate button is NOT displayed self.client.login(username=self.student.username, password=self.PASSWORD) response = self.client.get(reverse("dashboard")) self.assertNotContains(response, "donate-container")
def test_hide_nav(self): # Create the course modes for mode in ["honor", "verified"]: CourseModeFactory(mode_slug=mode, course_id=self.course.id) # Load the track selection page url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) # Verify that the header navigation links are hidden for the edx.org version self.assertNotContains(response, "How it Works") self.assertNotContains(response, "Find courses") self.assertNotContains(response, "Schools & Partners")
def test_congrats_on_enrollment_message(self, create_enrollment): # Create the course mode CourseModeFactory.create(mode_slug='verified', course_id=self.course.id) if create_enrollment: CourseEnrollmentFactory(is_active=True, course_id=self.course.id, user=self.user) # Check whether congratulations message is shown on the page # This should *only* be shown when an enrollment exists url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) response = self.client.get(url) if create_enrollment: self.assertContains(response, "Congratulations! You are now enrolled in") else: self.assertNotContains( response, "Congratulations! You are now enrolled in")
def test_enterprise_learner_context_with_multiple_organizations(self): """ Test: Track selection page should show the enterprise context message with multiple organization names if user belongs to the Enterprise. """ # Create the course modes for mode in ('audit', 'honor', 'verified'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) catalog_integration = self.create_catalog_integration() UserFactory(username=catalog_integration.service_username) self.mock_enterprise_learner_api() self.mock_course_discovery_api_for_catalog_contains( catalog_id=1, course_run_ids=[str(self.course.id)]) # Creating organization for i in xrange(2): test_organization_data = { 'name': 'test organization ' + str(i), 'short_name': 'test_organization_' + str(i), 'description': 'Test Organization Description', 'active': True, 'logo': '/logo_test1.png/' } test_org = organizations_api.add_organization( organization_data=test_organization_data) organizations_api.add_organization_course( organization_data=test_org, course_id=unicode(self.course.id)) # User visits the track selection page directly without ever enrolling url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) self.assertEquals(response.status_code, 200) self.assertContains( response, 'Welcome, {username}! You are about to enroll in {course_name}, from test organization 0 and ' 'test organization 1, sponsored by TestShib. Please select your enrollment information below.' .format(username=self.user.username, course_name=self.course.display_name_with_default_escaped))
def _check_verification_status_off(self, mode, value): """ Check that the css class and the status message are not in the dashboard html. """ CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) CourseEnrollment.enroll(self.user, self.course.location.course_key, mode=mode) if mode == 'verified': # Simulate a successful verification attempt attempt = SoftwareSecurePhotoVerification.objects.create(user=self.user) attempt.mark_ready() attempt.submit() attempt.approve() response = self.client.get(reverse('dashboard')) if mode == 'audit': # Audit mode does not have a banner. Assert no banner element. self.assertEqual(pq(response.content)(".sts-enrollment").length, 0) else: self.assertNotContains(response, "class=\"course {0}\"".format(mode)) self.assertNotContains(response, value)
def test_generate_example_certs_with_verified_mode(self): # Create verified and honor modes for the course CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug='honor') CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug='verified') # Generate certificates for the course with self._mock_xqueue() as mock_queue: certs_api.generate_example_certificates(self.COURSE_KEY) # Verify that the appropriate certs were added to the queue self._assert_certs_in_queue(mock_queue, 2) # Verify that the certificate status is "started" self._assert_cert_status( { 'description': 'verified', 'status': 'started' }, { 'description': 'honor', 'status': 'started' })
def setUp(self): super(EntitlementViewSetTest, self).setUp() self.user = UserFactory(is_staff=True) self.client.login(username=self.user.username, password=TEST_PASSWORD) self.course = CourseFactory() self.course_mode = CourseModeFactory( course_id=self.course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1)) self.entitlements_list_url = reverse( 'entitlements_api:v1:entitlements-list')
def test_expired_course(self): """ Ensure that a user accessing an expired course sees a redirect to the student dashboard, not a 404. """ CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime( 2010, 1, 1)) course = CourseFactory.create(start=THREE_YEARS_AGO) url = course_home_url(course) for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]: CourseModeFactory.create(course_id=course.id, mode_slug=mode) # assert that an if an expired audit user tries to access the course they are redirected to the dashboard audit_user = UserFactory(password=self.TEST_PASSWORD) self.client.login(username=audit_user.username, password=self.TEST_PASSWORD) audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT) audit_enrollment.created = THREE_YEARS_AGO + timedelta(days=1) audit_enrollment.save() ScheduleFactory(enrollment=audit_enrollment) response = self.client.get(url) expiration_date = strftime_localized( course.start + timedelta(weeks=4) + timedelta(days=1), u'%b %-d, %Y') expected_params = QueryDict(mutable=True) course_name = CourseOverview.get_from_id( course.id).display_name_with_default expected_params[ 'access_response_error'] = u'Access to {run} expired on {expiration_date}'.format( run=course_name, expiration_date=expiration_date) expected_url = '{url}?{params}'.format( url=reverse('dashboard'), params=expected_params.urlencode()) self.assertRedirects(response, expected_url)
def test_course_closed(self): for mode in ["honor", "verified"]: CourseModeFactory(mode_slug=mode, course_id=self.course.id) self.course.enrollment_end = datetime(2015, 01, 01) modulestore().update_item(self.course, self.user.id) url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.get(url) # URL-encoded version of 1/1/15, 12:00 AM redirect_url = reverse( 'dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM' self.assertRedirects(response, redirect_url)
def test_choose_mode_redirect(self, course_mode, expected_redirect): # Create the course modes for mode in ('audit', 'honor', 'verified'): min_price = 0 if mode in ["honor", "audit"] else 1 CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price) # Choose the mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[course_mode]) # Verify the redirect if expected_redirect == 'dashboard': redirect_url = reverse('dashboard') elif expected_redirect == 'start-flow': redirect_url = reverse( 'verify_student_start_flow', kwargs={'course_id': unicode(self.course.id)} ) else: self.fail("Must provide a valid redirect URL name") self.assertRedirects(response, redirect_url)
def setUp(self): """ Create a course and user, then log in. Also creates a course mode.""" # This function is a simplified version of test_views.EnrollmentTest.setUp super(EnrollmentEmailNotificationTest, self).setUp() # Pass emit_signals when creating the course so it would be cached # as a CourseOverview. self.course = CourseFactory.create(emit_signals=True) self.user = UserFactory.create( username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD, ) self.client.login(username=self.USERNAME, password=self.PASSWORD) CourseModeFactory.create( course_id=self.course.id, mode_slug=CourseMode.DEFAULT_MODE_SLUG, mode_display_name=CourseMode.DEFAULT_MODE_SLUG, )
def setUp(self): super(SupportViewEnrollmentsTests, self).setUp() SupportStaffRole().add_users(self.user) self.course = CourseFactory(display_name=u'teꜱᴛ') self.student = UserFactory.create(username='******', email='*****@*****.**', password='******') for mode in ( CourseMode.AUDIT, CourseMode.PROFESSIONAL, CourseMode.CREDIT_MODE, CourseMode.NO_ID_PROFESSIONAL_MODE, CourseMode.VERIFIED, CourseMode.HONOR ): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) self.verification_deadline = VerificationDeadline( course_key=self.course.id, deadline=datetime.now(UTC) + timedelta(days=365) ) self.verification_deadline.save() CourseEnrollmentFactory.create(mode=CourseMode.AUDIT, user=self.student, course_id=self.course.id) self.url = reverse('support:enrollment_list', kwargs={'username_or_email': self.student.username})
def test_no_id_redirect(self): # Create the course modes CourseModeFactory.create(mode_slug=CourseMode.NO_ID_PROFESSIONAL_MODE, course_id=self.course.id, min_price=100) # Enroll the user in the test course CourseEnrollmentFactory(is_active=False, mode=CourseMode.NO_ID_PROFESSIONAL_MODE, course_id=self.course.id, user=self.user) # Configure whether we're upgrading or not url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) response = self.client.get(url) # Check whether we were correctly redirected purchase_workflow = "?purchase_workflow=single" start_flow_url = reverse('verify_student_start_flow', args=[six.text_type(self.course.id) ]) + purchase_workflow self.assertRedirects(response, start_flow_url)
def create_self_paced_course_run(days_till_start=1, org_id=None): """ Create a new course run and course modes. All date-related arguments are relative to the current date-time (now) unless otherwise specified. Both audit and verified `CourseMode` objects will be created for the course run. Arguments: days_till_start (int): Number of days until the course starts. org_id (string): String org id to assign the course to (default: None; use CourseFactory default) """ now = datetime.now(utc) course = CourseFactory.create(start=now + timedelta(days=days_till_start), self_paced=True, org=org_id if org_id else 'TestedX') CourseModeFactory(course_id=course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory(course_id=course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=now + timedelta(days=100)) return course
def handle(self, *args, **options): courses = modulestore().get_courses() # Find the largest auto-generated course, and pick the next sequence id to generate the next # course with. max_org_sequence_id = max([0] + [int(course.org[4:]) for course in courses if course.org.startswith('org.')]) XMODULE_FACTORY_LOCK.enable() CourseFactory.reset_sequence(max_org_sequence_id + 1, force=True) course = CourseFactory.create( start=datetime.datetime.today() - datetime.timedelta(days=30), end=datetime.datetime.today() + datetime.timedelta(days=30), number=factory.Sequence('schedules_test_course_{}'.format), display_name=factory.Sequence(u'Schedules Test Course {}'.format), ) XMODULE_FACTORY_LOCK.disable() course_overview = CourseOverview.load_from_module_store(course.id) CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.AUDIT) CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.VERIFIED) CourseDurationLimitExpirySchedule.create_batch(20, enrollment__course=course_overview) ScheduleConfigFactory.create(site=Site.objects.get(name='example.com'))
def test_donate_button(self, course_modes, enrollment_mode, show_donate): # Enable the enrollment success message self._configure_message_timeout(10000) # Enable donations DonationConfiguration(enabled=True).save() # Create the course mode(s) for mode, min_price in course_modes: CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price) self.enrollment.mode = enrollment_mode self.enrollment.save() # Check that the donate button is or is not displayed self.client.login(username=self.student.username, password=self.PASSWORD) response = self.client.get(reverse("dashboard")) if show_donate: self.assertContains(response, "donate-container") else: self.assertNotContains(response, "donate-container")
def setUp(self): super(FinancialAssistanceToolTest, self).setUp() self.course_financial_mode = CourseModeFactory( course_id=self.course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=self.now + datetime.timedelta(days=1), ) DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True) self.request = RequestFactory().request() crum.set_current_request(self.request) self.addCleanup(crum.set_current_request, None) # baseline course enrollment, future upgrade deadline self.enrollment = CourseEnrollmentFactory( course_id=self.course.id, mode=CourseMode.AUDIT, course=self.course_overview, ) self.request.user = self.enrollment.user # enrollment where learner has upgraded self.enrollment_upgraded = CourseEnrollmentFactory( course_id=self.course.id, mode=CourseMode.VERIFIED, course=self.course_overview, ) # course enrollment for mock: upgrade deadline in the past self.enrollment_deadline_past = self.enrollment self.enrollment_deadline_past.course_upgrade_deadline = self.now - datetime.timedelta( days=1) self.enrollment_deadline_past.save() # course enrollment for mock: no upgrade deadline self.enrollment_deadline_missing = self.enrollment self.enrollment_deadline_missing.course_upgrade_deadline = None self.enrollment_deadline_missing.save()
def test_ended_course(self): course = CourseFactory.create( start=now() - timedelta(days=60), end=now() - timedelta(days=30), run='test', display_name='test', ) CourseModeFactory.create( mode_slug=CourseMode.VERIFIED, course_id=course.id, min_price=10, sku=six.text_type(uuid4().hex) ) response = self.client.get(self.url, {'course_id': course.id}) self.assertEqual(response.status_code, 200) expected = { 'show_upsell': False, 'upsell_flag': True, 'course_running': False, } self.assertEqual(response.data, expected)
def setUp(self): super(TestReverifyService, self).setUp() self.user = UserFactory.create(username="******", password="******") course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course_key = course.id CourseModeFactory( mode_slug="verified", course_id=self.course_key, min_price=100, suggested_prices='' ) self.item = ItemFactory.create(parent=course, category='chapter', display_name='Test Section')
def create_course_run( days_till_start=1, days_till_end=14, days_till_upgrade_deadline=4, days_till_verification_deadline=14, ): """ Create a new course run and course modes. All date-related arguments are relative to the current date-time (now) unless otherwise specified. Both audit and verified `CourseMode` objects will be created for the course run. Arguments: days_till_end (int): Number of days until the course ends. days_till_start (int): Number of days until the course starts. days_till_upgrade_deadline (int): Number of days until the course run's upgrade deadline. days_till_verification_deadline (int): Number of days until the course run's verification deadline. If this value is set to `None` no deadline will be verification deadline will be created. """ now = datetime.now(utc) course = CourseFactory.create(start=now + timedelta(days=days_till_start)) course.end = None if days_till_end is not None: course.end = now + timedelta(days=days_till_end) CourseModeFactory(course_id=course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory(course_id=course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=now + timedelta(days=days_till_upgrade_deadline)) if days_till_verification_deadline is not None: VerificationDeadline.objects.create( course_key=course.id, deadline=now + timedelta(days=days_till_verification_deadline)) return course
def setup_course_and_user( self, days_till_start=1, days_till_end=14, days_till_upgrade_deadline=4, enrollment_mode=CourseMode.VERIFIED, days_till_verification_deadline=14, verification_status=None, ): """Set up the course and user for this test.""" now = datetime.now(pytz.UTC) self.course = CourseFactory.create( # pylint: disable=attribute-defined-outside-init start=now + timedelta(days=days_till_start), end=now + timedelta(days=days_till_end), ) self.user = UserFactory.create() # pylint: disable=attribute-defined-outside-init if enrollment_mode is not None and days_till_upgrade_deadline is not None: CourseModeFactory.create( course_id=self.course.id, mode_slug=enrollment_mode, expiration_datetime=now + timedelta(days=days_till_upgrade_deadline)) CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user, mode=enrollment_mode) else: CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user) if days_till_verification_deadline is not None: VerificationDeadline.objects.create( course_key=self.course.id, deadline=now + timedelta(days=days_till_verification_deadline)) if verification_status is not None: SoftwareSecurePhotoVerificationFactory.create( user=self.user, status=verification_status)
def test_remember_donation_for_course(self): # Create the course modes CourseModeFactory.create(mode_slug='honor', course_id=self.course.id) CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, min_price=1) # Choose the mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['verified']) # Expect that the contribution amount is stored in the user's session self.assertIn('donation_for_course', self.client.session) self.assertIn(unicode(self.course.id), self.client.session['donation_for_course']) actual_amount = self.client.session['donation_for_course'][unicode( self.course.id)] expected_amount = decimal.Decimal( self.POST_PARAMS_FOR_COURSE_MODE['verified']['contribution']) self.assertEqual(actual_amount, expected_amount)
def test_suggested_prices(self, price_list): # Create the course modes for mode in ('audit', 'honor'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, suggested_prices=price_list) # Enroll the user in the test course to emulate # automatic enrollment CourseEnrollmentFactory(is_active=True, course_id=self.course.id, user=self.user) # Verify that the prices render correctly response = self.client.get( reverse('course_modes_choose', args=[unicode(self.course.id)]), follow=False, ) self.assertEquals(response.status_code, 200)
def _configure(self, mode, upgrade_deadline=None, verification_deadline=None): """Configure course modes and deadlines. """ course_mode = CourseModeFactory.create( mode_slug=mode, mode_display_name=mode, ) if upgrade_deadline is not None: course_mode.upgrade_deadline = upgrade_deadline course_mode.save() VerificationDeadline.set_deadline(self.course.id, verification_deadline) return CourseModeForm(instance=course_mode)
def _admin_form(self, mode, upgrade_deadline=None): """Load the course mode admin form. """ course_mode = CourseModeFactory.create( course_id=self.course.id, mode_slug=mode, ) return CourseModeForm({ "course_id": unicode(self.course.id), "mode_slug": mode, "mode_display_name": mode, "_expiration_datetime": upgrade_deadline, "currency": "usd", "min_price": 10, }, instance=course_mode)
def test_successful_default_enrollment(self): self.mock_enterprise_learner_api() self.mock_enterprise_course_enrollment_get_api() # Create the course modes for mode in (CourseMode.DEFAULT_MODE_SLUG, 'verified'): CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) # Enroll the user in the default mode (honor) to emulate # automatic enrollment params = { 'enrollment_action': 'enroll', 'course_id': unicode(self.course.id) } self.client.post(reverse('change_enrollment'), params) # Explicitly select the honor mode (POST request) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[CourseMode.DEFAULT_MODE_SLUG]) # Verify that the user's enrollment remains unchanged mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) self.assertEqual(mode, CourseMode.DEFAULT_MODE_SLUG) self.assertEqual(is_active, True)
def test_upgrade_deadline(self): """ The property should use either the CourseMode or related Schedule to determine the deadline. """ course = CourseFactory(self_paced=True) course_mode = CourseModeFactory( course_id=course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=1)) enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT) self.assertEqual(Schedule.objects.all().count(), 0) self.assertEqual(enrollment.upgrade_deadline, course_mode.expiration_datetime)
def test_certificate_info_in_response(self): """ Test that certificate has been created and rendered properly with non-audit course mode. """ CourseModeFactory.create(course_id=self.course.id, mode_slug='verified') response = self.client.ajax_post( self._url(), data=CERTIFICATE_JSON_WITH_SIGNATORIES) self.assertEqual(response.status_code, 201) # in html response result = self.client.get_html(self._url()) self.assertIn('Test certificate', result.content) self.assertIn('Test description', result.content) # in JSON response response = self.client.get_json(self._url()) data = json.loads(response.content.decode('utf-8')) self.assertEquals(len(data), 1) self.assertEqual(data[0]['name'], 'Test certificate') self.assertEqual(data[0]['description'], 'Test description') self.assertEqual(data[0]['version'], CERTIFICATE_SCHEMA_VERSION)