Files
edx-platform/common/test/acceptance/tests/lms/test_lms_dashboard.py
aarif 45338f4160 changes made to sanitize the urls for consistent comparison
changes made to finalize the url sanitization to make url comparison consistent

changes made to avoid running sanitize in python 2

changes made to substitute proper query param in url for comparison

changes made to split and compare the query parameter with expected url

updated the split logic to properly split/slice url parts for comparison

updated the dashboard template to remove encode and avoid bytes encoded embeded url

updated the dashboard template to enclose social media urls with unicode
2019-10-25 15:20:32 +05:00

439 lines
18 KiB
Python

# -*- coding: utf-8 -*-
"""
End-to-end tests for the main LMS Dashboard (aka, Student Dashboard).
"""
from __future__ import absolute_import
import datetime
import re
import six
from six.moves.urllib.parse import unquote # pylint: disable=import-error
from common.test.acceptance.fixtures.course import CourseFixture
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
from common.test.acceptance.pages.lms.dashboard import DashboardPage
from common.test.acceptance.tests.helpers import UniqueCourseTest, generate_course_key
DEFAULT_SHORT_DATE_FORMAT = u'{dt:%b} {dt.day}, {dt.year}'
TEST_DATE_FORMAT = u'{dt:%b} {dt.day}, {dt.year} {dt.hour:02}:{dt.minute:02}'
class BaseLmsDashboardTest(UniqueCourseTest):
""" Base test suite for the LMS Student Dashboard """
def setUp(self):
"""
Initializes the components (page objects, courses, users) for this test suite
"""
# Some parameters are provided by the parent setUp() routine, such as the following:
# self.course_id, self.course_info, self.unique_id
super(BaseLmsDashboardTest, self).setUp()
# Load page objects for use by the tests
self.dashboard_page = DashboardPage(self.browser)
# Configure some aspects of the test course and install the settings into the course
self.course_fixture = CourseFixture(
self.course_info["org"],
self.course_info["number"],
self.course_info["run"],
self.course_info["display_name"],
)
self.course_fixture.add_advanced_settings({
u"social_sharing_url": {u"value": "http://custom/course/url"}
})
self.course_fixture.install()
self.username = "test_{uuid}".format(uuid=self.unique_id[0:6])
self.email = "{user}@example.com".format(user=self.username)
# Create the test user, register them for the course, and authenticate
AutoAuthPage(
self.browser,
username=self.username,
email=self.email,
course_id=self.course_id
).visit()
# Navigate the authenticated, enrolled user to the dashboard page and get testing!
self.dashboard_page.visit()
class BaseLmsDashboardTestMultiple(UniqueCourseTest):
""" Base test suite for the LMS Student Dashboard with Multiple Courses"""
def setUp(self):
"""
Initializes the components (page objects, courses, users) for this test suite
"""
# Some parameters are provided by the parent setUp() routine, such as the following:
# self.course_id, self.course_info, self.unique_id
super(BaseLmsDashboardTestMultiple, self).setUp()
# Load page objects for use by the tests
self.dashboard_page = DashboardPage(self.browser)
# Configure some aspects of the test course and install the settings into the course
self.courses = {
'A': {
'org': 'test_org',
'number': self.unique_id,
'run': 'test_run_A',
'display_name': 'Test Course A',
'enrollment_mode': 'audit',
'cert_name_long': 'Certificate of Audit Achievement'
},
'B': {
'org': 'test_org',
'number': self.unique_id,
'run': 'test_run_B',
'display_name': 'Test Course B',
'enrollment_mode': 'verified',
'cert_name_long': 'Certificate of Verified Achievement'
},
'C': {
'org': 'test_org',
'number': self.unique_id,
'run': 'test_run_C',
'display_name': 'Test Course C',
'enrollment_mode': 'credit',
'cert_name_long': 'Certificate of Credit Achievement'
}
}
self.username = "test_{uuid}".format(uuid=self.unique_id[0:6])
self.email = "{user}@example.com".format(user=self.username)
self.course_keys = {}
self.course_fixtures = {}
for key, value in six.iteritems(self.courses):
course_key = generate_course_key(
value['org'],
value['number'],
value['run'],
)
course_fixture = CourseFixture(
value['org'],
value['number'],
value['run'],
value['display_name'],
)
course_fixture.add_advanced_settings({
u"social_sharing_url": {u"value": "http://custom/course/url"},
u"cert_name_long": {u"value": value['cert_name_long']}
})
course_fixture.install()
self.course_keys[key] = course_key
self.course_fixtures[key] = course_fixture
# Create the test user, register them for the course, and authenticate
AutoAuthPage(
self.browser,
username=self.username,
email=self.email,
course_id=course_key,
enrollment_mode=value['enrollment_mode']
).visit()
# Navigate the authenticated, enrolled user to the dashboard page and get testing!
self.dashboard_page.visit()
class LmsDashboardPageTest(BaseLmsDashboardTest):
""" Test suite for the LMS Student Dashboard page """
shard = 9
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
"""
course_listings = self.dashboard_page.get_course_listings()
self.assertEqual(len(course_listings), 1)
def test_dashboard_social_sharing_feature(self):
"""
Validate the behavior of the social sharing feature
"""
twitter_widget = self.dashboard_page.get_course_social_sharing_widget('twitter')
twitter_url = ("https://twitter.com/intent/tweet?text=Testing+feature%3A%20http%3A%2F%2Fcustom%2Fcourse%2Furl"
"%3Futm_campaign%3Dsocial-sharing-db%26utm_medium%3Dsocial%26utm_source%3Dtwitter")
self.assertEqual(twitter_widget.attrs('title')[0], 'Share on Twitter')
self.assertEqual(twitter_widget.attrs('data-tooltip')[0], 'Share on Twitter')
self.assertEqual(twitter_widget.attrs('target')[0], '_blank')
self._assert_social_url(twitter_widget.attrs('href')[0], unquote(twitter_url), r"\'(.*?)\'\,")
self._assert_social_url(twitter_widget.attrs('onclick')[0], unquote(twitter_url), r"\'(.*?)\'\,")
facebook_widget = self.dashboard_page.get_course_social_sharing_widget('facebook')
facebook_url = ("https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fcustom%2Fcourse%2Furl%3F"
"utm_campaign%3Dsocial-sharing-db%26utm_medium%3Dsocial%26utm_source%3Dfacebook&"
"quote=I%27m+taking+Test+Course")
self.assertEqual(facebook_widget.attrs('title')[0], 'Share on Facebook')
self.assertEqual(facebook_widget.attrs('data-tooltip')[0], 'Share on Facebook')
self.assertEqual(facebook_widget.attrs('target')[0], '_blank')
self._assert_social_url(facebook_widget.attrs('onclick')[0], unquote(facebook_url), r"\'(.*?);")
self._assert_social_url(facebook_widget.attrs('href')[0], unquote(facebook_url), r"^(.*)\;")
def _assert_social_url(self, url, expected_url, pattern):
"""
will remove byte characters from specific query parameter
"""
url = unquote(url)
social_url_search = re.search(pattern, url)
url_split = (social_url_search.group(1) if social_url_search else url).split('?')
query_parameters = url_split[2].split('&')
urls = url_split[:2] + query_parameters
for query_parameter in urls:
self.assertIn(query_parameter.strip("'"), expected_url)
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 = DEFAULT_SHORT_DATE_FORMAT.format(dt=course_end_date)
expected_course_date = u"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 = DEFAULT_SHORT_DATE_FORMAT.format(dt=course_start_date)
expected_course_date = u"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 = DEFAULT_SHORT_DATE_FORMAT.format(dt=course_start_date)
expected_course_date = u"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 = TEST_DATE_FORMAT.format(dt=course_start_date)
expected_course_date = u"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)
def test_advertised_start_date(self):
"""
Scenario:
Course Date should be advertised start date
if the course on student dashboard has `Course Advertised Start` set.
As a Student,
Given that I have enrolled to a course
And the course has `Course Advertised Start` set.
When I visit dashboard page
Then the advertised start date should be displayed rather course start date"
"""
course_start_date = self.now + datetime.timedelta(days=2)
course_advertised_start = "Winter 2018"
self.course_fixture.add_course_details({
'start_date': course_start_date,
})
self.course_fixture.configure_course()
self.course_fixture.add_advanced_settings({
u"advertised_start": {u"value": course_advertised_start}
})
self.course_fixture._add_advanced_settings()
expected_course_date = u"Starts - {start_date}".format(start_date=course_advertised_start)
self.dashboard_page.visit()
course_date = self.dashboard_page.get_course_date()
self.assertEqual(course_date, expected_course_date)
def test_profile_img_alt_empty(self):
"""
Validate value of profile image alt attribue is null
"""
profile_img = self.dashboard_page.get_profile_img()
self.assertEqual(profile_img.attrs('alt')[0], '')
class LmsDashboardCourseUnEnrollDialogMessageTest(BaseLmsDashboardTestMultiple):
"""
Class to test lms student dashboard unenroll dialog messages.
"""
shard = 23
def test_audit_course_run_unenroll_dialog_msg(self):
"""
Validate unenroll dialog message when user clicks unenroll button for a audit course
"""
self.dashboard_page.visit()
dialog_message = self.dashboard_page.view_course_unenroll_dialog_message(str(self.course_keys['A']))
course_number = self.courses['A']['number']
course_name = self.courses['A']['display_name']
expected_track_message = u'Are you sure you want to unenroll from' + \
u' <span id="unenroll_course_name">' + course_name + u'</span>' + \
u' (<span id="unenroll_course_number">' + course_number + u'</span>)?'
self.assertEqual(dialog_message['track-info'][0], expected_track_message)
def test_verified_course_run_unenroll_dialog_msg(self):
"""
Validate unenroll dialog message when user clicks unenroll button for a verified course passed refund
deadline
"""
self.dashboard_page.visit()
dialog_message = self.dashboard_page.view_course_unenroll_dialog_message(str(self.course_keys['B']))
course_number = self.courses['B']['number']
course_name = self.courses['B']['display_name']
cert_long_name = self.courses['B']['cert_name_long']
expected_track_message = u'Are you sure you want to unenroll from the verified' + \
u' <span id="unenroll_cert_name">' + cert_long_name + u'</span>' + \
u' track of <span id="unenroll_course_name">' + course_name + u'</span>' + \
u' (<span id="unenroll_course_number">' + course_number + u'</span>)?'
expected_refund_message = u'The refund deadline for this course has passed,so you will not receive a refund.'
self.assertEqual(dialog_message['track-info'][0], expected_track_message)
self.assertEqual(dialog_message['refund-info'][0], expected_refund_message)
class LmsDashboardA11yTest(BaseLmsDashboardTestMultiple):
"""
Class to test lms student dashboard accessibility.
"""
a11y = True
def test_dashboard_course_listings_a11y(self):
"""
Test the accessibility of the course listings
"""
self.dashboard_page.a11y_audit.config.set_rules({
"ignore": [
'aria-valid-attr', # TODO: LEARNER-6611 & LEARNER-6865
'button-name', # TODO: AC-935
'landmark-no-duplicate-banner', # TODO: AC-934
'landmark-complementary-is-top-level', # TODO: AC-939
'region' # TODO: AC-932
]
})
course_listings = self.dashboard_page.get_courses()
self.assertEqual(len(course_listings), 3)
self.dashboard_page.a11y_audit.check_for_accessibility_errors()