feat: add SVGs for icons in Track Selection, refactor URLs and tests (#28701)
REV-2133
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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, '<span class="award-icon">')
|
||||
self.assertContains(response, '<span class="popover-icon">')
|
||||
self.assertContains(response, '<span class="note-icon">')
|
||||
|
||||
# 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, '<li class="collapsible-item">')
|
||||
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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -58,6 +58,8 @@ from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
});
|
||||
</script>
|
||||
</%block>
|
||||
|
||||
## REV-2133 TODO: check with Website if this is required in the new Track Selection template.
|
||||
<%static:webpack entry="Currency">
|
||||
new Currency();
|
||||
</%static:webpack>
|
||||
@@ -95,10 +97,12 @@ from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
<div class="choice-title"><h4>${_("Earn a certificate")}</h4></div>
|
||||
<div class="choice-bullets">
|
||||
<ul>
|
||||
<li>${Text(_("Showcase a {link_start}verified certificate{link_end} of completion on your resumé to advance your career")).format(
|
||||
link_start=HTML('<b><u><a class="verified" href="https://www.edx.org/verified-certificate" target="_blank">'),
|
||||
link_end=HTML('</a></u></b>'),
|
||||
)}</li>
|
||||
<li>
|
||||
${Text(_("Showcase a {link_start}verified certificate{link_end} of completion on your resumé to advance your career")).format(
|
||||
link_start=HTML('<b><u><a class="verified" href="{track_verified_url}" target="_blank">').format(track_verified_url=track_links['verified_certificate']),
|
||||
link_end=HTML('</a></u></b>')
|
||||
)}
|
||||
</li>
|
||||
<li>${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('<b>'),
|
||||
end_bold=HTML('</b>'),
|
||||
@@ -110,16 +114,18 @@ from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
end_bold=HTML('</b>'),
|
||||
)}
|
||||
<span class="popover-icon">
|
||||
<i class="fa fa-question-circle" aria-hidden="true"></i>
|
||||
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.0212 6C12.0212 9.31444 9.33472 12 6.02124 12C2.70776 12 0.0212402 9.31444 0.0212402 6C0.0212402 2.68749 2.70776 0 6.02124 0C9.33472 0 12.0212 2.68749 12.0212 6ZM6.02124 7.20968C5.4066 7.20968 4.90834 7.70794 4.90834 8.32258C4.90834 8.93722 5.4066 9.43548 6.02124 9.43548C6.63588 9.43548 7.13414 8.93722 7.13414 8.32258C7.13414 7.70794 6.63588 7.20968 6.02124 7.20968ZM4.96464 3.20937L5.1441 6.49969C5.1525 6.65366 5.2798 6.77419 5.43399 6.77419H6.60849C6.76268 6.77419 6.88998 6.65366 6.89838 6.49969L7.07785 3.20937C7.08692 3.04306 6.95451 2.90323 6.78796 2.90323H5.2545C5.08795 2.90323 4.95556 3.04306 4.96464 3.20937Z" fill="#00262B"/>
|
||||
</svg>
|
||||
<span class="popover">
|
||||
${Text(_("{link_start}Learn more{link_end} about course access")).format(
|
||||
link_start=HTML('<u><a href="https://support.edx.org/hc/en-us/articles/360013426573-What-are-the-differences-between-audit-free-and-verified-paid-courses-" target="_blank">'),
|
||||
link_end=HTML('</a></u>'),
|
||||
link_start=HTML('<u><a href="{track_comparison_url}" target="_blank">').format(track_comparison_url=track_links['learn_more']),
|
||||
link_end=HTML('</a></u>')
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
<li class="collapsible-item">${Text(_("Support our {start_bold}non-profit mission{end_bold} to increase access to high-quality education for everyone, everywhere")).format(
|
||||
<li class="collapsible-item">${Text(_("Support our {start_bold}mission{end_bold} to increase access to high-quality education for everyone, everywhere")).format(
|
||||
start_bold=HTML('<b>'),
|
||||
end_bold=HTML('</b>'),
|
||||
)}</li>
|
||||
@@ -147,7 +153,11 @@ from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
</div>
|
||||
</div>
|
||||
<div class="verified-note mr-md-2">
|
||||
<span class="note-icon"><i class="fa fa-lightbulb-o fa-lg" aria-hidden="true"></i></span>
|
||||
<span class="note-icon">
|
||||
<svg width="16" height="24" viewBox="0 0 16 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4.22074C5.59364 4.22074 3.63636 6.12408 3.63636 8.46413C3.63636 8.85488 3.96182 9.17137 4.36364 9.17137C4.76545 9.17137 5.09091 8.85488 5.09091 8.46413C5.09091 6.9038 6.39636 5.6352 8 5.6352C8.40182 5.6352 8.72727 5.31871 8.72727 4.92797C8.72727 4.53722 8.40182 4.22074 8 4.22074ZM4.36636 20.9808C4.36636 21.1201 4.40864 21.2558 4.48818 21.3716L5.60227 23C5.73727 23.1971 5.96455 23.3156 6.20773 23.3156H9.79182C10.0355 23.3156 10.2627 23.1971 10.3973 23L11.5114 21.3716C11.5905 21.2558 11.6327 21.1196 11.6332 20.9808L11.6355 19.0722H4.36455L4.36636 20.9808ZM8 0.68457C3.35091 0.68457 0 4.35202 0 8.46413C0 10.4254 0.747727 12.2147 1.98 13.5818C2.73636 14.4212 3.92273 16.1809 4.36273 17.6555V17.6582H6.54455V17.6529C6.54409 17.442 6.51182 17.2325 6.44682 17.0309C6.19273 16.2437 5.40955 14.168 3.62091 12.1833C2.68727 11.1476 2.18818 9.83395 2.18409 8.46413C2.175 5.20909 4.89636 2.80627 8 2.80627C11.2082 2.80627 13.8182 5.34435 13.8182 8.46413C13.8182 9.83307 13.3073 11.1538 12.3795 12.1833C10.6018 14.1551 9.815 16.2265 9.55682 17.0217C9.49019 17.2261 9.45615 17.4393 9.45591 17.6537V17.6582H11.6377V17.656C12.0777 16.1809 13.2641 14.4212 14.0205 13.5823C15.2523 12.2147 16 10.4254 16 8.46413C16 4.16769 12.4182 0.68457 8 0.68457Z" fill="black"/>
|
||||
</svg>
|
||||
</span>
|
||||
<div class="note-info">${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('<b>'),
|
||||
end_bold=HTML('</b>'),
|
||||
@@ -176,7 +186,6 @@ from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
</div>
|
||||
<ul class="list-actions">
|
||||
<li class="action action-select track-selection-button">
|
||||
<input type="hidden" name="contribution" />
|
||||
<button id="track_selection_audit" type="submit" name="audit_mode">
|
||||
<span>${_('Continue')}</span>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user