Centralize the logic for choosing between MFE and Legacy-frontend courseware within three new functions: * courseware_mfe_is_active * courseware_mfe_is_visible * courseware_legacy_is_visible This allows us to create another new function: * get_courseware_url which can be called anywhere in LMS/Studio to get the canonical URL to courseware content (whether it be MFE or Legacy). In future commits we we begin using get_courseware_url throughout the platform. TNL-7796
258 lines
9.0 KiB
Python
258 lines
9.0 KiB
Python
"""
|
|
Test some of the functions in url_helpers
|
|
"""
|
|
from unittest import mock
|
|
|
|
import ddt
|
|
|
|
from xmodule.modulestore import ModuleStoreEnum
|
|
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
|
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
|
|
|
from .. import url_helpers
|
|
|
|
|
|
def _patch_courseware_mfe_is_active(ret_val):
|
|
return mock.patch.object(
|
|
url_helpers,
|
|
'courseware_mfe_is_active',
|
|
return_value=ret_val,
|
|
)
|
|
|
|
|
|
@ddt.ddt
|
|
class GetCoursewareUrlTests(SharedModuleStoreTestCase):
|
|
"""
|
|
Test get_courseware_url.
|
|
|
|
Mock out `courseware_mfe_is_active`; that is tested elseware.
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
"""
|
|
Set up data used across test functions.
|
|
"""
|
|
# pylint: disable=super-method-not-called
|
|
with super().setUpClassAndTestData():
|
|
cls.items = cls.create_test_courses()
|
|
|
|
@classmethod
|
|
def create_test_courses(cls):
|
|
"""
|
|
We build two simple course structures (one using Split, the other Old Mongo).
|
|
Each course structure is a non-branching tree from the root Course block down
|
|
to the Component-level problem block; that is, we make one item for each course
|
|
hierarchy level.
|
|
|
|
For easy access in the test functions, we return them in a dict like this:
|
|
{
|
|
"split": {
|
|
"course_run": <course block for Split Mongo course>,
|
|
"section": <chapter block in course run>
|
|
"subsection": <sequence block in section>
|
|
"unit": <vertical block in subsection>
|
|
"component": <problem block in unit>
|
|
},
|
|
"mongo": {
|
|
"course_run": <course block for (deprecated) Old Mongo course>,
|
|
... etc ...
|
|
}
|
|
}
|
|
"""
|
|
|
|
# Make Split Mongo course.
|
|
with cls.store.default_store(ModuleStoreEnum.Type.split):
|
|
course_run = CourseFactory.create(
|
|
org='TestX',
|
|
number='UrlHelpers',
|
|
run='split',
|
|
display_name='URL Helpers Test Course',
|
|
)
|
|
with cls.store.bulk_operations(course_run.id):
|
|
section = ItemFactory.create(
|
|
parent_location=course_run.location,
|
|
category='chapter',
|
|
display_name="Generated Section",
|
|
)
|
|
subsection = ItemFactory.create(
|
|
parent_location=section.location,
|
|
category='sequential',
|
|
display_name="Generated Subsection",
|
|
)
|
|
unit = ItemFactory.create(
|
|
parent_location=subsection.location,
|
|
category='vertical',
|
|
display_name="Generated Unit",
|
|
)
|
|
component = ItemFactory.create(
|
|
parent_location=unit.location,
|
|
category='problem',
|
|
display_name="Generated Problem Component",
|
|
)
|
|
|
|
# Make (deprecated) Old Mongo course.
|
|
with cls.store.default_store(ModuleStoreEnum.Type.mongo):
|
|
deprecated_course_run = CourseFactory.create(
|
|
org='TestX',
|
|
number='UrlHelpers',
|
|
run='mongo',
|
|
display_name='URL Helpers Test Course (Deprecated)',
|
|
)
|
|
with cls.store.bulk_operations(deprecated_course_run.id):
|
|
deprecated_section = ItemFactory.create(
|
|
parent_location=deprecated_course_run.location,
|
|
category='chapter',
|
|
display_name="Generated Section",
|
|
)
|
|
deprecated_subsection = ItemFactory.create(
|
|
parent_location=deprecated_section.location,
|
|
category='sequential',
|
|
display_name="Generated Subsection",
|
|
)
|
|
deprecated_unit = ItemFactory.create(
|
|
parent_location=deprecated_subsection.location,
|
|
category='vertical',
|
|
display_name="Generated Unit",
|
|
)
|
|
deprecated_component = ItemFactory.create(
|
|
parent_location=deprecated_unit.location,
|
|
category='problem',
|
|
display_name="Generated Problem Component",
|
|
)
|
|
|
|
return {
|
|
ModuleStoreEnum.Type.split: {
|
|
'course_run': course_run,
|
|
'section': section,
|
|
'subsection': subsection,
|
|
'unit': unit,
|
|
'component': component,
|
|
},
|
|
ModuleStoreEnum.Type.mongo: {
|
|
'course_run': deprecated_course_run,
|
|
'section': deprecated_section,
|
|
'subsection': deprecated_subsection,
|
|
'unit': deprecated_unit,
|
|
'component': deprecated_component,
|
|
}
|
|
}
|
|
|
|
@ddt.data(
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'mfe',
|
|
'course_run',
|
|
'http://learning-mfe/course/course-v1:TestX+UrlHelpers+split'
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'mfe',
|
|
'section',
|
|
(
|
|
'http://learning-mfe/course/course-v1:TestX+UrlHelpers+split' +
|
|
'/block-v1:TestX+UrlHelpers+split+type@chapter+block@Generated_Section'
|
|
),
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'mfe',
|
|
'subsection',
|
|
(
|
|
'http://learning-mfe/course/course-v1:TestX+UrlHelpers+split' +
|
|
'/block-v1:TestX+UrlHelpers+split+type@sequential+block@Generated_Subsection'
|
|
),
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'mfe',
|
|
'unit',
|
|
(
|
|
'http://learning-mfe/course/course-v1:TestX+UrlHelpers+split' +
|
|
'/block-v1:TestX+UrlHelpers+split+type@sequential+block@Generated_Subsection' +
|
|
'/block-v1:TestX+UrlHelpers+split+type@vertical+block@Generated_Unit'
|
|
),
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'mfe',
|
|
'component',
|
|
(
|
|
'http://learning-mfe/course/course-v1:TestX+UrlHelpers+split' +
|
|
'/block-v1:TestX+UrlHelpers+split+type@sequential+block@Generated_Subsection' +
|
|
'/block-v1:TestX+UrlHelpers+split+type@vertical+block@Generated_Unit'
|
|
),
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'legacy',
|
|
'course_run',
|
|
'/courses/course-v1:TestX+UrlHelpers+split/courseware',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'legacy',
|
|
'subsection',
|
|
'/courses/course-v1:TestX+UrlHelpers+split/courseware/Generated_Section/Generated_Subsection/',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'legacy',
|
|
'unit',
|
|
'/courses/course-v1:TestX+UrlHelpers+split/courseware/Generated_Section/Generated_Subsection/1',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.split,
|
|
'legacy',
|
|
'component',
|
|
'/courses/course-v1:TestX+UrlHelpers+split/courseware/Generated_Section/Generated_Subsection/1',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.mongo,
|
|
'legacy',
|
|
'course_run',
|
|
'/courses/TestX/UrlHelpers/mongo/courseware',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.mongo,
|
|
'legacy',
|
|
'subsection',
|
|
'/courses/TestX/UrlHelpers/mongo/courseware/Generated_Section/Generated_Subsection/',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.mongo,
|
|
'legacy',
|
|
'unit',
|
|
'/courses/TestX/UrlHelpers/mongo/courseware/Generated_Section/Generated_Subsection/1',
|
|
),
|
|
(
|
|
ModuleStoreEnum.Type.mongo,
|
|
'legacy',
|
|
'component',
|
|
'/courses/TestX/UrlHelpers/mongo/courseware/Generated_Section/Generated_Subsection/1',
|
|
),
|
|
)
|
|
@ddt.unpack
|
|
def test_get_courseware_url(
|
|
self,
|
|
store_type,
|
|
active_experience,
|
|
structure_level,
|
|
expected_path,
|
|
):
|
|
"""
|
|
Given:
|
|
* a `store_type` ('split' or [old] 'mongo'),
|
|
* an `active_experience` ('mfe' or 'legacy'),
|
|
* and a `structure_level` ('course_run', 'section', 'subsection', 'unit', or 'component'),
|
|
|
|
check that the expected path (URL without querystring) is returned by `get_courseware_url`.
|
|
"""
|
|
block = self.items[store_type][structure_level]
|
|
with _patch_courseware_mfe_is_active(active_experience == 'mfe') as mock_mfe_is_active:
|
|
url = url_helpers.get_courseware_url(block.location)
|
|
path = url.split('?')[0]
|
|
assert path == expected_path
|
|
course_run = self.items[store_type]['course_run']
|
|
mock_mfe_is_active.assert_called_once_with(course_run.id)
|