Credit progress page formatting bugfixes.
* Correctly format the student's full name on the progress page. * Add tests for progress page credit requirements display. * Display grade percentage for credit requirement on progress page
This commit is contained in:
@@ -6,7 +6,6 @@ import datetime
|
||||
|
||||
from mock import patch
|
||||
import pytz
|
||||
from mock import patch
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
147
lms/djangoapps/courseware/tests/test_credit_requirements.py
Normal file
147
lms/djangoapps/courseware/tests/test_credit_requirements.py
Normal file
@@ -0,0 +1,147 @@
|
||||
"""
|
||||
Tests for credit requirement display on the progress page.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from mock import patch
|
||||
from pytz import UTC
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from student.tests.factories import UserFactory, CourseEnrollmentFactory
|
||||
from util.date_utils import get_time_display, DEFAULT_SHORT_DATE_FORMAT
|
||||
|
||||
from openedx.core.djangoapps.credit import api as credit_api
|
||||
from openedx.core.djangoapps.credit.models import CreditCourse
|
||||
|
||||
|
||||
@patch.dict(settings.FEATURES, {"ENABLE_CREDIT_ELIGIBILITY": True})
|
||||
class ProgressPageCreditRequirementsTest(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests for credit requirement display on the progress page.
|
||||
"""
|
||||
|
||||
USERNAME = "bob"
|
||||
PASSWORD = "test"
|
||||
USER_FULL_NAME = "Bob"
|
||||
|
||||
MIN_GRADE_REQ_DISPLAY = "Final Grade Credit Requirement"
|
||||
VERIFICATION_REQ_DISPLAY = "Midterm Exam Credit Requirement"
|
||||
|
||||
def setUp(self):
|
||||
super(ProgressPageCreditRequirementsTest, self).setUp()
|
||||
|
||||
# Create a course and configure it as a credit course
|
||||
self.course = CourseFactory.create()
|
||||
CreditCourse.objects.create(course_key=self.course.id, enabled=True) # pylint: disable=no-member
|
||||
|
||||
# Configure credit requirements (passing grade and in-course reverification)
|
||||
credit_api.set_credit_requirements(
|
||||
self.course.id, # pylint: disable=no-member
|
||||
[
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": self.MIN_GRADE_REQ_DISPLAY,
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"namespace": "reverification",
|
||||
"name": "midterm",
|
||||
"display_name": self.VERIFICATION_REQ_DISPLAY,
|
||||
"criteria": {}
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
# Create a user and log in
|
||||
self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
|
||||
self.user.profile.name = self.USER_FULL_NAME
|
||||
self.user.profile.save()
|
||||
|
||||
result = self.client.login(username=self.USERNAME, password=self.PASSWORD)
|
||||
self.assertTrue(result, msg="Could not log in")
|
||||
|
||||
# Enroll the user in the course as "verified"
|
||||
self.enrollment = CourseEnrollmentFactory(
|
||||
user=self.user,
|
||||
course_id=self.course.id, # pylint: disable=no-member
|
||||
mode="verified"
|
||||
)
|
||||
|
||||
def test_credit_requirements_maybe_eligible(self):
|
||||
# The user hasn't satisfied any of the credit requirements yet, but she
|
||||
# also hasn't failed any.
|
||||
response = self._get_progress_page()
|
||||
|
||||
# Expect that the requirements are displayed
|
||||
self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY)
|
||||
self.assertContains(response, self.VERIFICATION_REQ_DISPLAY)
|
||||
self.assertContains(response, "Upcoming")
|
||||
self.assertContains(
|
||||
response,
|
||||
"{}, you have not yet met the requirements for credit".format(self.USER_FULL_NAME)
|
||||
)
|
||||
|
||||
def test_credit_requirements_eligible(self):
|
||||
# Mark the user as eligible for all requirements
|
||||
credit_api.set_credit_requirement_status(
|
||||
self.user.username, self.course.id,
|
||||
"grade", "grade",
|
||||
status="satisfied",
|
||||
reason={"final_grade": 0.95}
|
||||
)
|
||||
|
||||
credit_api.set_credit_requirement_status(
|
||||
self.user.username, self.course.id,
|
||||
"reverification", "midterm",
|
||||
status="satisfied", reason={}
|
||||
)
|
||||
|
||||
# Check the progress page display
|
||||
response = self._get_progress_page()
|
||||
self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY)
|
||||
self.assertContains(response, self.VERIFICATION_REQ_DISPLAY)
|
||||
self.assertContains(
|
||||
response,
|
||||
"{}, you have met the requirements for credit in this course.".format(self.USER_FULL_NAME)
|
||||
)
|
||||
self.assertContains(response, "Verified on {date}".format(date=self._now_formatted_date()))
|
||||
self.assertContains(response, "95%")
|
||||
|
||||
def test_credit_requirements_not_eligible(self):
|
||||
# Mark the user as having failed both requirements
|
||||
credit_api.set_credit_requirement_status(
|
||||
self.user.username, self.course.id,
|
||||
"reverification", "midterm",
|
||||
status="failed", reason={}
|
||||
)
|
||||
|
||||
# Check the progress page display
|
||||
response = self._get_progress_page()
|
||||
self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY)
|
||||
self.assertContains(response, self.VERIFICATION_REQ_DISPLAY)
|
||||
self.assertContains(
|
||||
response,
|
||||
"{}, you are no longer eligible for credit in this course.".format(self.USER_FULL_NAME)
|
||||
)
|
||||
self.assertContains(response, "Verification Failed")
|
||||
|
||||
def _get_progress_page(self):
|
||||
"""Load the progress page for the course the user is enrolled in. """
|
||||
url = reverse("progress", kwargs={"course_id": unicode(self.course.id)})
|
||||
return self.client.get(url)
|
||||
|
||||
def _now_formatted_date(self):
|
||||
"""Retrieve the formatted current date. """
|
||||
return get_time_display(
|
||||
datetime.datetime.now(UTC),
|
||||
DEFAULT_SHORT_DATE_FORMAT,
|
||||
settings.TIME_ZONE
|
||||
)
|
||||
@@ -105,13 +105,13 @@ from django.utils.http import urlquote_plus
|
||||
<h2>${_("Requirements for Course Credit")}</h2>
|
||||
</div>
|
||||
%if credit_course_requirements['eligibility_status'] == 'not_eligible':
|
||||
<span class="eligibility_msg">${student.get_full_name()}, ${_("You are no longer eligible for this course.")}</span>
|
||||
<span class="eligibility_msg">${_("{student_name}, you are no longer eligible for credit in this course.").format(student_name=student.profile.name)}</span>
|
||||
%elif credit_course_requirements['eligibility_status'] == 'eligible':
|
||||
<span class="eligibility_msg">${student.get_full_name()}, ${_("You have met the requirements for credit in this course.")}
|
||||
<span class="eligibility_msg">${_("{student_name}, you have met the requirements for credit in this course.").format(student_name=student.profile.name)}
|
||||
${_("{link} to purchase course credit.").format(link="<a href={url}>{url_name}</a>".format(url = reverse('dashboard'), url_name = _('Go to your dashboard')))}
|
||||
</span>
|
||||
%elif credit_course_requirements['eligibility_status'] == 'partial_eligible':
|
||||
<span>${_("{student_name}, you have not yet met the requirements for credit.").format(student_name=student.get_full_name())}</span>
|
||||
<span>${_("{student_name}, you have not yet met the requirements for credit.").format(student_name=student.profile.name)}</span>
|
||||
%endif
|
||||
<a href="${settings.CREDIT_HELP_LINK_URL}" class="credit-help"><i class="fa fa-question"></i><span class="sr">${_("Information about course credit requirements")}</span></a><br>
|
||||
<div class="requirement-container" data-eligible="${credit_course_requirements['eligibility_status']}">
|
||||
@@ -127,7 +127,13 @@ from django.utils.http import urlquote_plus
|
||||
<span>${_("Verification Failed" )}</span>
|
||||
%elif requirement['status'] == 'satisfied':
|
||||
<i class="fa fa-check"></i>
|
||||
% if requirement['namespace'] == 'reverification':
|
||||
<span>Verified on ${get_time_display(requirement['status_date'], DEFAULT_SHORT_DATE_FORMAT, settings.TIME_ZONE)}</span>
|
||||
% elif requirement['namespace'] == 'grade' and 'final_grade' in requirement['reason']:
|
||||
<span>${int(requirement['reason']['final_grade'] * 100)}%</span>
|
||||
% else:
|
||||
<span>Completed</span>
|
||||
% endif
|
||||
%endif
|
||||
%else:
|
||||
<span class="not-achieve">${_("Upcoming")}</span>
|
||||
|
||||
@@ -294,6 +294,7 @@ def get_credit_requirement_status(course_key, username, namespace=None, name=Non
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "In Course Reverification",
|
||||
"criteria": {},
|
||||
"reason": {},
|
||||
"status": "failed",
|
||||
"status_date": "2015-06-26 07:49:13",
|
||||
},
|
||||
@@ -302,6 +303,7 @@ def get_credit_requirement_status(course_key, username, namespace=None, name=Non
|
||||
"name": "i4x://edX/DemoX/proctoring-block/final_uuid",
|
||||
"display_name": "Proctored Mid Term Exam",
|
||||
"criteria": {},
|
||||
"reason": {},
|
||||
"status": "satisfied",
|
||||
"status_date": "2015-06-26 11:07:42",
|
||||
},
|
||||
@@ -310,7 +312,8 @@ def get_credit_requirement_status(course_key, username, namespace=None, name=Non
|
||||
"name": "i4x://edX/DemoX/proctoring-block/final_uuid",
|
||||
"display_name": "Minimum Passing Grade",
|
||||
"criteria": {"min_grade": 0.8},
|
||||
"status": "failed",
|
||||
"reason": {"final_grade": 0.95},
|
||||
"status": "satisfied",
|
||||
"status_date": "2015-06-26 11:07:44",
|
||||
},
|
||||
]
|
||||
@@ -329,6 +332,7 @@ def get_credit_requirement_status(course_key, username, namespace=None, name=Non
|
||||
"name": requirement.name,
|
||||
"display_name": requirement.display_name,
|
||||
"criteria": requirement.criteria,
|
||||
"reason": requirement_status.reason if requirement_status else None,
|
||||
"status": requirement_status.status if requirement_status else None,
|
||||
"status_date": requirement_status.modified if requirement_status else None,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user