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:
Will Daly
2015-07-19 15:34:11 -07:00
parent 80cf4d6ecb
commit d3f58b689f
4 changed files with 161 additions and 5 deletions

View File

@@ -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

View 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
)

View File

@@ -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>

View File

@@ -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,
})