Files
edx-platform/common/djangoapps/student/tests/test_certificates.py
Sagirov Evgeniy c5d1807c81 feat!: remove most Old Mongo functionality (#31134)
This commit leaves behind just enough Old Mongo (DraftModulestore)
functionality to allow read-only access to static assets and the
root CourseBlock. It removes:

* create/update operations
* child/parent traversal
* inheritance related code

It also removes or converts tests for this functionality.

The ability to read from the root CourseBlock was maintained for
backwards compatibility, since top-level course settings are often
stored here, and this is used by various parts of the codebase,
like displaying dashboards and re-building CourseOverview models.

Any attempt to read the contents of a course by getting the
CourseBlock's children will return an empty list (i.e. it will look
empty).

This commit does _not_ delete content on MongoDB or run any sort of
data migration or cleanup.
2023-09-06 10:01:31 -04:00

215 lines
7.5 KiB
Python

"""Tests for display of certificates on the student dashboard. """
import datetime
from unittest.mock import patch
import ddt
from django.conf import settings
from django.test.utils import override_settings
from django.urls import reverse
from pytz import UTC
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.data import CertificatesDisplayBehaviors
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from openedx.core.djangolib.testing.utils import skip_unless_lms
from lms.djangoapps.certificates.api import get_certificate_url
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.tests.factories import (
GeneratedCertificateFactory,
LinkedInAddToProfileConfigurationFactory
)
# pylint: disable=no-member
PAST_DATE = datetime.datetime.now(UTC) - datetime.timedelta(days=2)
FUTURE_DATE = datetime.datetime.now(UTC) + datetime.timedelta(days=2)
class CertificateDisplayTestBase(SharedModuleStoreTestCase):
"""Tests display of certificates on the student dashboard. """
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
USERNAME = "test_user"
PASSWORD = "password"
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.course = CourseFactory()
cls.course.certificates_display_behavior = CertificatesDisplayBehaviors.EARLY_NO_INFO
with cls.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, cls.course.id):
cls.store.update_item(cls.course, cls.USERNAME)
def setUp(self):
super().setUp()
self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
result = self.client.login(username=self.USERNAME, password=self.PASSWORD)
assert result, 'Could not log in'
def _check_linkedin_visibility(self, is_visible):
"""
Performs assertions on the Dashboard
"""
response = self.client.get(reverse('dashboard'))
if is_visible:
self.assertContains(response, 'Add Certificate to LinkedIn Profile')
else:
self.assertNotContains(response, 'Add Certificate to LinkedIn Profile')
def _create_certificate(self, enrollment_mode):
"""Simulate that the user has a generated certificate. """
CourseEnrollmentFactory.create(
user=self.user,
course_id=self.course.id,
mode=enrollment_mode)
return GeneratedCertificateFactory(
user=self.user,
course_id=self.course.id,
mode=enrollment_mode,
status=CertificateStatuses.downloadable,
grade=0.98,
)
@ddt.ddt
@skip_unless_lms
class CertificateDashboardMessageDisplayTest(CertificateDisplayTestBase):
"""
Tests the certificates messages for a course in the dashboard.
"""
ENABLED_SIGNALS = ['course_published']
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.course.certificates_display_behavior = CertificatesDisplayBehaviors.END_WITH_DATE
cls.course.save()
cls.store.update_item(cls.course, cls.USERNAME)
def _check_message(self, visible_date): # lint-amnesty, pylint: disable=missing-function-docstring
response = self.client.get(reverse('dashboard'))
is_past = visible_date < datetime.datetime.now(UTC)
if is_past:
test_message = 'Your grade and certificate will be ready after'
self.assertNotContains(response, test_message)
self.assertNotContains(response, "View Test_Certificate")
else:
test_message = 'Congratulations! Your certificate is ready.'
self.assertContains(response, test_message)
self.assertNotContains(response, "View Test_Certificate")
@ddt.data(
(CertificatesDisplayBehaviors.END, True),
(CertificatesDisplayBehaviors.END, False),
(CertificatesDisplayBehaviors.END_WITH_DATE, True),
(CertificatesDisplayBehaviors.END_WITH_DATE, False)
)
@ddt.unpack
def test_certificate_available_date(self, certificates_display_behavior, past_date):
cert = self._create_certificate('verified')
cert.status = CertificateStatuses.downloadable
cert.save()
self.course.certificates_display_behavior = certificates_display_behavior
if certificates_display_behavior == CertificatesDisplayBehaviors.END:
if past_date:
self.course.end = PAST_DATE
else:
self.course.end = FUTURE_DATE
if certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE:
if past_date:
self.course.certificate_available_date = PAST_DATE
else:
self.course.certificate_available_date = FUTURE_DATE
self.course.save()
self.store.update_item(self.course, self.USERNAME)
self._check_message(PAST_DATE if past_date else FUTURE_DATE)
@ddt.ddt
@skip_unless_lms
class CertificateDisplayTest(CertificateDisplayTestBase):
"""
Tests of certificate display.
"""
@ddt.data('verified', 'honor', 'professional')
def test_unverified_certificate_message(self, enrollment_mode):
cert = self._create_certificate(enrollment_mode)
cert.status = CertificateStatuses.unverified
cert.save()
response = self.client.get(reverse('dashboard'))
self.assertContains(
response,
'do not have a current verified identity with {platform_name}'
.format(platform_name=settings.PLATFORM_NAME))
def test_post_to_linkedin_visibility(self):
"""
Verifies that the post certificate to linked button
does not appear by default (when config is not set)
Then Verifies that the post certificate to linked button appears
as expected once a config is set
"""
self._create_certificate('honor')
# until we set up the configuration, the LinkedIn action
# button should not be visible
self._check_linkedin_visibility(False)
LinkedInAddToProfileConfigurationFactory()
# now we should see it
self._check_linkedin_visibility(True)
@ddt.ddt
@skip_unless_lms
class CertificateDisplayTestLinkedHtmlView(CertificateDisplayTestBase):
"""
Tests of linked student certificates.
"""
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.course.cert_html_view_enabled = True
certificates = [
{
'id': 0,
'name': 'Test Name',
'description': 'Test Description',
'is_active': True,
'signatories': [],
'version': 1
}
]
cls.course.certificates = {'certificates': certificates}
cls.course.save()
cls.store.update_item(cls.course, cls.USERNAME)
@ddt.data('verified')
@override_settings(CERT_NAME_SHORT='Test_Certificate')
@patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': True})
def test_linked_student_to_web_view_credential(self, enrollment_mode):
cert = self._create_certificate(enrollment_mode)
test_url = get_certificate_url(course_id=self.course.id, uuid=cert.verify_uuid)
response = self.client.get(reverse('dashboard'))
self.assertContains(response, 'View my Test_Certificate')
self.assertContains(response, test_url)