Merge pull request #9822 from edx/saleem-latif/SOL-565
saleem-latif/SOL-565
This commit is contained in:
@@ -98,6 +98,7 @@ DEFAULT_SHORT_DATE_FORMAT = "%b %d, %Y"
|
||||
DEFAULT_LONG_DATE_FORMAT = "%A, %B %d, %Y"
|
||||
DEFAULT_TIME_FORMAT = "%I:%M:%S %p"
|
||||
DEFAULT_DATE_TIME_FORMAT = "%b %d, %Y at %H:%M"
|
||||
DEFAULT_DAY_AND_TIME_FORMAT = "%A at %-I%P"
|
||||
|
||||
|
||||
def strftime_localized(dtime, format): # pylint: disable=redefined-builtin
|
||||
@@ -147,6 +148,8 @@ def strftime_localized(dtime, format): # pylint: disable=redefined-builtin
|
||||
format = ugettext("DATE_TIME_FORMAT")
|
||||
if format == "DATE_TIME_FORMAT":
|
||||
format = DEFAULT_DATE_TIME_FORMAT
|
||||
elif format == "DAY_AND_TIME":
|
||||
format = DEFAULT_DAY_AND_TIME_FORMAT
|
||||
elif format == "TIME":
|
||||
format = "%X"
|
||||
|
||||
@@ -204,7 +207,7 @@ def strftime_localized(dtime, format): # pylint: disable=redefined-builtin
|
||||
|
||||
return part
|
||||
|
||||
formatted_date = re.sub(r"%.|%", process_percent_code, format)
|
||||
formatted_date = re.sub(r"%-.|%.|%", process_percent_code, format)
|
||||
return formatted_date
|
||||
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ class StrftimeLocalizedTest(unittest.TestCase):
|
||||
(u'%Y년 %m월 %d일', u"2013년 02월 14일"),
|
||||
("%a, %b %d, %Y", "Thu, Feb 14, 2013"),
|
||||
("%I:%M:%S %p", "04:41:17 PM"),
|
||||
("%A at %-I%P", "Thursday at 4pm"),
|
||||
)
|
||||
def test_usual_strftime_behavior(self, (fmt, expected)):
|
||||
dtime = datetime(2013, 02, 14, 16, 41, 17)
|
||||
@@ -157,6 +158,7 @@ class StrftimeLocalizedTest(unittest.TestCase):
|
||||
("SHORT_DATE", "Feb 14, 2013"),
|
||||
("LONG_DATE", "Thursday, February 14, 2013"),
|
||||
("TIME", "04:41:17 PM"),
|
||||
("DAY_AND_TIME", "Thursday at 4pm"),
|
||||
("%x %X!", "Feb 14, 2013 04:41:17 PM!"),
|
||||
)
|
||||
def test_shortcuts(self, (fmt, expected)):
|
||||
|
||||
@@ -6,6 +6,7 @@ allows us to share code between the CourseDescriptor and CourseOverview
|
||||
classes, which both need these type of functions.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from base64 import b32encode
|
||||
|
||||
from django.utils.timezone import UTC
|
||||
@@ -105,6 +106,18 @@ def has_course_ended(end_date):
|
||||
return datetime.now(UTC()) > end_date if end_date is not None else False
|
||||
|
||||
|
||||
def course_starts_within(start_date, look_ahead_days):
|
||||
"""
|
||||
Given a course's start datetime and look ahead days, returns True if
|
||||
course's start date falls within look ahead days otherwise False
|
||||
|
||||
Arguments:
|
||||
start_date (datetime): The start datetime of the course in question.
|
||||
look_ahead_days (int): number of days to see in future for course start date.
|
||||
"""
|
||||
return datetime.now(UTC()) + timedelta(days=look_ahead_days) > start_date
|
||||
|
||||
|
||||
def course_start_date_is_default(start, advertised_start):
|
||||
"""
|
||||
Returns whether a course's start date hasn't yet been set.
|
||||
@@ -132,7 +145,7 @@ def _datetime_to_string(date_time, format_string, strftime_localized):
|
||||
# TODO: Is manually appending UTC really the right thing to do here? What if date_time isn't UTC?
|
||||
result = strftime_localized(date_time, format_string)
|
||||
return (
|
||||
result + u" UTC" if format_string in ['DATE_TIME', 'TIME']
|
||||
result + u" UTC" if format_string in ['DATE_TIME', 'TIME', 'DAY_AND_TIME']
|
||||
else result
|
||||
)
|
||||
|
||||
|
||||
@@ -152,6 +152,21 @@ class CourseFixture(XBlockContainerFixture):
|
||||
"""
|
||||
return "<CourseFixture: org='{org}', number='{number}', run='{run}'>".format(**self._course_dict)
|
||||
|
||||
def add_course_details(self, course_details):
|
||||
"""
|
||||
Add course details to dict of course details to be updated when configure_course or install is called.
|
||||
|
||||
Arguments:
|
||||
Dictionary containing key value pairs for course updates,
|
||||
e.g. {'start_date': datetime.now() }
|
||||
"""
|
||||
if 'start_date' in course_details:
|
||||
course_details['start_date'] = course_details['start_date'].isoformat()
|
||||
if 'end_date' in course_details:
|
||||
course_details['end_date'] = course_details['end_date'].isoformat()
|
||||
|
||||
self._course_details.update(course_details)
|
||||
|
||||
def add_update(self, update):
|
||||
"""
|
||||
Add an update to the course. `update` should be a `CourseUpdateDesc`.
|
||||
@@ -201,6 +216,12 @@ class CourseFixture(XBlockContainerFixture):
|
||||
|
||||
return self
|
||||
|
||||
def configure_course(self):
|
||||
"""
|
||||
Configure Course Settings, take new course settings from self._course_details dict object
|
||||
"""
|
||||
self._configure_course()
|
||||
|
||||
@property
|
||||
def _course_location(self):
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"""
|
||||
Student dashboard page.
|
||||
"""
|
||||
|
||||
from bok_choy.page_object import PageObject
|
||||
from . import BASE_URL
|
||||
|
||||
@@ -157,6 +156,18 @@ class DashboardPage(PageObject):
|
||||
""" Retrieves the specified social sharing widget by its classification """
|
||||
return self.q(css='a.action-{}'.format(widget_name))
|
||||
|
||||
def get_courses(self):
|
||||
"""
|
||||
Get all courses shown in the dashboard
|
||||
"""
|
||||
return self.q(css='ul.listing-courses .course-item')
|
||||
|
||||
def get_course_date(self):
|
||||
"""
|
||||
Get course date of the first course from dashboard
|
||||
"""
|
||||
return self.q(css='ul.listing-courses .course-item .info-date-block').first.text[0]
|
||||
|
||||
def click_username_dropdown(self):
|
||||
"""
|
||||
Click username dropdown.
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
"""
|
||||
End-to-end tests for the main LMS Dashboard (aka, Student Dashboard).
|
||||
"""
|
||||
import datetime
|
||||
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...fixtures.course import CourseFixture
|
||||
from ...pages.lms.auto_auth import AutoAuthPage
|
||||
from ...pages.lms.dashboard import DashboardPage
|
||||
|
||||
DEFAULT_SHORT_DATE_FORMAT = "%b %d, %Y"
|
||||
DEFAULT_DAY_AND_TIME_FORMAT = "%A at %-I%P"
|
||||
|
||||
|
||||
class BaseLmsDashboardTest(UniqueCourseTest):
|
||||
""" Base test suite for the LMS Student Dashboard """
|
||||
@@ -51,6 +56,12 @@ class BaseLmsDashboardTest(UniqueCourseTest):
|
||||
class LmsDashboardPageTest(BaseLmsDashboardTest):
|
||||
""" Test suite for the LMS Student Dashboard page """
|
||||
|
||||
def setUp(self):
|
||||
super(LmsDashboardPageTest, self).setUp()
|
||||
|
||||
# now datetime for usage in tests
|
||||
self.now = datetime.datetime.now()
|
||||
|
||||
def test_dashboard_course_listings(self):
|
||||
"""
|
||||
Perform a general validation of the course listings section
|
||||
@@ -81,3 +92,128 @@ class LmsDashboardPageTest(BaseLmsDashboardTest):
|
||||
self.assertEqual(facebook_widget.attrs('target')[0], '_blank')
|
||||
self.assertIn(facebook_url, facebook_widget.attrs('href')[0])
|
||||
self.assertIn(facebook_url, facebook_widget.attrs('onclick')[0])
|
||||
|
||||
def test_ended_course_date(self):
|
||||
"""
|
||||
Scenario:
|
||||
Course Date should have the format 'Ended - Sep 23, 2015'
|
||||
if the course on student dashboard has ended.
|
||||
|
||||
As a Student,
|
||||
Given that I have enrolled to a course
|
||||
And the course has ended in the past
|
||||
When I visit dashboard page
|
||||
Then the course date should have the following format "Ended - %b %d, %Y" e.g. "Ended - Sep 23, 2015"
|
||||
"""
|
||||
course_start_date = datetime.datetime(1970, 1, 1)
|
||||
course_end_date = self.now - datetime.timedelta(days=90)
|
||||
|
||||
self.course_fixture.add_course_details({'start_date': course_start_date,
|
||||
'end_date': course_end_date})
|
||||
self.course_fixture.configure_course()
|
||||
|
||||
end_date = course_end_date.strftime(DEFAULT_SHORT_DATE_FORMAT)
|
||||
expected_course_date = "Ended - {end_date}".format(end_date=end_date)
|
||||
|
||||
# reload the page for changes to course date changes to appear in dashboard
|
||||
self.dashboard_page.visit()
|
||||
|
||||
course_date = self.dashboard_page.get_course_date()
|
||||
|
||||
# Test that proper course date with 'ended' message is displayed if a course has already ended
|
||||
self.assertEqual(course_date, expected_course_date)
|
||||
|
||||
def test_running_course_date(self):
|
||||
"""
|
||||
Scenario:
|
||||
Course Date should have the format 'Started - Sep 23, 2015'
|
||||
if the course on student dashboard is running.
|
||||
|
||||
As a Student,
|
||||
Given that I have enrolled to a course
|
||||
And the course has started
|
||||
And the course is in progress
|
||||
When I visit dashboard page
|
||||
Then the course date should have the following format "Started - %b %d, %Y" e.g. "Started - Sep 23, 2015"
|
||||
"""
|
||||
course_start_date = datetime.datetime(1970, 1, 1)
|
||||
course_end_date = self.now + datetime.timedelta(days=90)
|
||||
|
||||
self.course_fixture.add_course_details({'start_date': course_start_date,
|
||||
'end_date': course_end_date})
|
||||
self.course_fixture.configure_course()
|
||||
|
||||
start_date = course_start_date.strftime(DEFAULT_SHORT_DATE_FORMAT)
|
||||
expected_course_date = "Started - {start_date}".format(start_date=start_date)
|
||||
|
||||
# reload the page for changes to course date changes to appear in dashboard
|
||||
self.dashboard_page.visit()
|
||||
|
||||
course_date = self.dashboard_page.get_course_date()
|
||||
|
||||
# Test that proper course date with 'started' message is displayed if a course is in running state
|
||||
self.assertEqual(course_date, expected_course_date)
|
||||
|
||||
def test_future_course_date(self):
|
||||
"""
|
||||
Scenario:
|
||||
Course Date should have the format 'Starts - Sep 23, 2015'
|
||||
if the course on student dashboard starts in future.
|
||||
|
||||
As a Student,
|
||||
Given that I have enrolled to a course
|
||||
And the course starts in future
|
||||
And the course does not start within 5 days
|
||||
When I visit dashboard page
|
||||
Then the course date should have the following format "Starts - %b %d, %Y" e.g. "Starts - Sep 23, 2015"
|
||||
"""
|
||||
course_start_date = self.now + datetime.timedelta(days=30)
|
||||
course_end_date = self.now + datetime.timedelta(days=365)
|
||||
|
||||
self.course_fixture.add_course_details({'start_date': course_start_date,
|
||||
'end_date': course_end_date})
|
||||
self.course_fixture.configure_course()
|
||||
|
||||
start_date = course_start_date.strftime(DEFAULT_SHORT_DATE_FORMAT)
|
||||
expected_course_date = "Starts - {start_date}".format(start_date=start_date)
|
||||
|
||||
# reload the page for changes to course date changes to appear in dashboard
|
||||
self.dashboard_page.visit()
|
||||
|
||||
course_date = self.dashboard_page.get_course_date()
|
||||
|
||||
# Test that proper course date with 'starts' message is displayed if a course is about to start in future,
|
||||
# and course does not start within 5 days
|
||||
self.assertEqual(course_date, expected_course_date)
|
||||
|
||||
def test_near_future_course_date(self):
|
||||
"""
|
||||
Scenario:
|
||||
Course Date should have the format 'Starts - Wednesday at 5am UTC'
|
||||
if the course on student dashboard starts within 5 days.
|
||||
|
||||
As a Student,
|
||||
Given that I have enrolled to a course
|
||||
And the course starts within 5 days
|
||||
When I visit dashboard page
|
||||
Then the course date should have the following format "Starts - %A at %-I%P UTC"
|
||||
e.g. "Starts - Wednesday at 5am UTC"
|
||||
"""
|
||||
course_start_date = self.now + datetime.timedelta(days=2)
|
||||
course_end_date = self.now + datetime.timedelta(days=365)
|
||||
|
||||
self.course_fixture.add_course_details({'start_date': course_start_date,
|
||||
'end_date': course_end_date})
|
||||
self.course_fixture.configure_course()
|
||||
|
||||
start_date = course_start_date.strftime(DEFAULT_DAY_AND_TIME_FORMAT)
|
||||
expected_course_date = "Starts - {start_date} UTC".format(start_date=start_date)
|
||||
|
||||
# reload the page for changes to course date changes to appear in dashboard
|
||||
self.dashboard_page.visit()
|
||||
|
||||
course_date = self.dashboard_page.get_course_date()
|
||||
|
||||
# Test that proper course date with 'starts' message is displayed if a course is about to start in future,
|
||||
# and course starts within 5 days
|
||||
self.assertEqual(course_date, expected_course_date)
|
||||
|
||||
@@ -94,6 +94,8 @@ from student.helpers import (
|
||||
${_("Started - {start_date}").format(start_date=course_overview.start_datetime_text("SHORT_DATE"))}
|
||||
% elif course_overview.start_date_is_still_default: # Course start date TBD
|
||||
${_("Coming Soon")}
|
||||
% elif course_overview.starts_within(days=5): # hasn't started yet
|
||||
${_("Starts - {start_date}").format(start_date=course_overview.start_datetime_text("DAY_AND_TIME"))}
|
||||
% else: # hasn't started yet
|
||||
${_("Starts - {start_date}").format(start_date=course_overview.start_datetime_text("SHORT_DATE"))}
|
||||
% endif
|
||||
|
||||
@@ -290,6 +290,13 @@ class CourseOverview(TimeStampedModel):
|
||||
"""
|
||||
return course_metadata_utils.has_course_ended(self.end)
|
||||
|
||||
def starts_within(self, days):
|
||||
"""
|
||||
Returns True if the course starts with-in given number of days otherwise returns False.
|
||||
"""
|
||||
|
||||
return course_metadata_utils.course_starts_within(self.start, days)
|
||||
|
||||
def start_datetime_text(self, format_string="SHORT_DATE"):
|
||||
"""
|
||||
Returns the desired text corresponding the course's start date and
|
||||
|
||||
Reference in New Issue
Block a user