From 519872a9930222f9d83689a4eaff4402f233c396 Mon Sep 17 00:00:00 2001 From: julianajlk Date: Wed, 15 Sep 2021 09:37:31 -0400 Subject: [PATCH] feat: add SVGs for icons in Track Selection, refactor URLs and tests (#28701) REV-2133 --- common/djangoapps/course_modes/helpers.py | 50 +++++++++++++++ .../course_modes/tests/test_views.py | 63 +++++++++++++++++++ common/djangoapps/course_modes/views.py | 5 +- lms/static/sass/views/_track_selection.scss | 5 ++ .../course_modes/track_selection.html | 29 ++++++--- 5 files changed, 141 insertions(+), 11 deletions(-) diff --git a/common/djangoapps/course_modes/helpers.py b/common/djangoapps/course_modes/helpers.py index ae0c3cf0a7..e17a03efc9 100644 --- a/common/djangoapps/course_modes/helpers.py +++ b/common/djangoapps/course_modes/helpers.py @@ -2,7 +2,9 @@ import logging +from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from urllib.parse import urljoin from requests.exceptions import ConnectionError, Timeout # pylint: disable=redefined-builtin from slumber.exceptions import SlumberBaseException @@ -123,3 +125,51 @@ def get_course_final_price(user, sku, course_price): result = int(result) return result + + +def get_verified_track_links(language): + """ + Format the URL's for Value Prop's Track Selection verified option, for the specified language. + + Arguments: + language (str): The language from the user's account settings. + + Returns: dict + Dictionary with URL's with verified certificate informational links. + If not edx.org, returns a dictionary with default URL's. + """ + support_url = settings.SUPPORT_SITE_LINK + root_url = settings.LMS_ROOT_URL + + enabled_languages = { + 'en': 'hc/en-us', + 'es-419': 'hc/es-419', + } + + # Add edX specific links only to edx.org + if root_url and 'edx.org' in root_url: + track_verified_url = urljoin(root_url, 'verified-certificate') + if support_url and 'support.edx.org' in support_url: + support_article_params = '/articles/360013426573-' + language_specific_params = { + 'en': 'What-are-the-differences-between-audit-free-and-verified-paid-courses-', + 'es-419': ('-Cu%C3%A1les-son-las-diferencias' + '-entre-los-cursos-de-auditor%C3%ADa-gratuitos-y-verificados-pagos-') + } + if language in ('es-419', 'es'): + full_params = enabled_languages['es-419'] + support_article_params + language_specific_params['es-419'] + else: + full_params = enabled_languages['en'] + support_article_params + language_specific_params['en'] + track_comparison_url = urljoin( + support_url, + full_params + ) + return { + 'verified_certificate': track_verified_url, + 'learn_more': track_comparison_url, + } + # Default URL's are used if not edx.org + return { + 'verified_certificate': root_url, + 'learn_more': support_url, + } diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py index dfc28b264b..0721322508 100644 --- a/common/djangoapps/course_modes/tests/test_views.py +++ b/common/djangoapps/course_modes/tests/test_views.py @@ -4,6 +4,7 @@ Tests for course_modes views. import decimal +import mock import unittest from datetime import datetime, timedelta from unittest.mock import patch @@ -21,6 +22,7 @@ from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from common.djangoapps.util.testing import UrlResetMixin from common.djangoapps.util.tests.mixins.discovery import CourseCatalogServiceMockMixin +from edx_toggles.toggles.testutils import override_waffle_flag from lms.djangoapps.commerce.tests import test_utils as ecomm_test_utils from lms.djangoapps.commerce.tests.mocks import mock_payment_processors from lms.djangoapps.verify_student.services import IDVerificationService @@ -31,6 +33,8 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory +from ..views import VALUE_PROP_TRACK_SELECTION_FLAG + @ddt.ddt @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @@ -507,6 +511,65 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM' self.assertRedirects(response, redirect_url) + # Value Prop TODO (REV-2378): remove waffle flag from tests once the new Track Selection template is rolled out. + # Other tests may need to be updated/removed to reflect the new page. + # The below test can be separated into multiple tests once un-happy path is implemented. + def test_new_track_selection(self): + # For the new track selection template to render, FBE must be fully on (gated_content and audit_access_deadline) + # and happy path conditions must be met: + # User can upgrade, FBE is fully on, and user is not an enterprise user. + + # Create the course modes and enroll the user + verified_mode = CourseModeFactory.create( + mode_slug='verified', + course_id=self.course_that_started.id, + min_price=149, + ) + CourseEnrollmentFactory( + is_active=True, + course_id=self.course_that_started.id, + user=self.user + ) + + # Check whether new track selection template is rendered. + # This should *only* be shown when the waffle flag is on. + with override_waffle_flag(VALUE_PROP_TRACK_SELECTION_FLAG, active=True): + with mock.patch( + 'openedx.features.content_type_gating.models.ContentTypeGatingConfig.enabled_for_enrollment', + return_value=True + ): + with mock.patch( + 'openedx.features.course_duration_limits.models.CourseDurationLimitConfig.enabled_for_enrollment', + return_value=True + ): + url = reverse('course_modes_choose', args=[str(self.course_that_started.id)]) + response = self.client.get(url) + + self.assertContains(response, "Choose a path for your course in") + + # Check if it displays the upgrade price for verified track and "Free" for audit track + self.assertContains(response, verified_mode.min_price) + self.assertContains(response, "Free") + + # Check for specific HTML elements + self.assertContains(response, '') + self.assertContains(response, '') + self.assertContains(response, '') + + # Check for upgrade button ID + self.assertContains(response, 'track_selection_upgrade') + # Check for audit button ID + self.assertContains(response, 'track_selection_audit') + + # Check for happy path messaging - verified + self.assertContains(response, '
  • ') + self.assertContains(response, 'access to all course activities') + self.assertContains(response, 'Full access') + # Check for happy path messaging - audit + self.assertContains(response, "discussion forums and non-graded assignments") + self.assertContains(response, "Get temporary access") + self.assertContains(response, "Access expires and all progress will be lost") + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): diff --git a/common/djangoapps/course_modes/views.py b/common/djangoapps/course_modes/views.py index ca7add09a7..9195eb1679 100644 --- a/common/djangoapps/course_modes/views.py +++ b/common/djangoapps/course_modes/views.py @@ -25,7 +25,7 @@ from ipware.ip import get_client_ip from opaque_keys.edx.keys import CourseKey from common.djangoapps.course_modes.models import CourseMode -from common.djangoapps.course_modes.helpers import get_course_final_price +from common.djangoapps.course_modes.helpers import get_course_final_price, get_verified_track_links from common.djangoapps.edxmako.shortcuts import render_to_response from common.djangoapps.util.date_utils import strftime_localized_html from edx_toggles.toggles import WaffleFlag @@ -248,6 +248,9 @@ class ChooseModeView(View): except TypeError: pass + language = get_language() + context['track_links'] = get_verified_track_links(language) + duration = get_user_course_duration(request.user, course) deadline = duration and get_user_course_expiration_date(request.user, course) if deadline: diff --git a/lms/static/sass/views/_track_selection.scss b/lms/static/sass/views/_track_selection.scss index 40acb9839e..b19cf99c3b 100644 --- a/lms/static/sass/views/_track_selection.scss +++ b/lms/static/sass/views/_track_selection.scss @@ -28,6 +28,10 @@ margin-bottom: 2rem; } + .track-selection-audit .choice-bullets li:last-child { + margin-bottom: 5rem; + } + .certificate-container { background-color: #EFF8FA; border: 1px solid #707070; @@ -116,6 +120,7 @@ .choice-bullets li { color: #454545; + margin-bottom: 1.25rem; } .choice-title { diff --git a/lms/templates/course_modes/track_selection.html b/lms/templates/course_modes/track_selection.html index 3e6fc741ed..f710fc167e 100644 --- a/lms/templates/course_modes/track_selection.html +++ b/lms/templates/course_modes/track_selection.html @@ -58,6 +58,8 @@ from openedx.core.djangolib.js_utils import js_escaped_string }); + +## REV-2133 TODO: check with Website if this is required in the new Track Selection template. <%static:webpack entry="Currency"> new Currency(); @@ -95,10 +97,12 @@ from openedx.core.djangolib.js_utils import js_escaped_string

    ${_("Earn a certificate")}

      -
    • ${Text(_("Showcase a {link_start}verified certificate{link_end} of completion on your resumé to advance your career")).format( - link_start=HTML(''), - link_end=HTML(''), - )}
    • +
    • + ${Text(_("Showcase a {link_start}verified certificate{link_end} of completion on your resumé to advance your career")).format( + link_start=HTML('').format(track_verified_url=track_links['verified_certificate']), + link_end=HTML('') + )} +
    • ${Text(_("Get {start_bold}access to all course activities{end_bold}, including both graded and non-graded assignments, while the course is running")).format( start_bold=HTML(''), end_bold=HTML(''), @@ -110,16 +114,18 @@ from openedx.core.djangolib.js_utils import js_escaped_string end_bold=HTML(''), )} - + + + ${Text(_("{link_start}Learn more{link_end} about course access")).format( - link_start=HTML(''), - link_end=HTML(''), + link_start=HTML('').format(track_comparison_url=track_links['learn_more']), + link_end=HTML('') )}
    • -
    • ${Text(_("Support our {start_bold}non-profit mission{end_bold} to increase access to high-quality education for everyone, everywhere")).format( +
    • ${Text(_("Support our {start_bold}mission{end_bold} to increase access to high-quality education for everyone, everywhere")).format( start_bold=HTML(''), end_bold=HTML(''), )}
    • @@ -147,7 +153,11 @@ from openedx.core.djangolib.js_utils import js_escaped_string
    - + + + + +
    ${Text(_("Studies show that those who choose this option are {start_bold}more engaged and motivated{end_bold} to complete their courses")).format( start_bold=HTML(''), end_bold=HTML(''), @@ -176,7 +186,6 @@ from openedx.core.djangolib.js_utils import js_escaped_string
    • -