Commit dbc99ef8 by Calen Pennington

Implement children for pure XBlocks in edx-platform

This requires fixing the javascript api implementation, and adding
an implementation of get_block to the ModuleSystem api.

However, the implementation is incomplete, due to mismatches between
the expectations of XModule and XBlock.

Also adds tests using the Acid block to make sure that the javascript
and python apis for children are working correctly.
parent 3093efc8
...@@ -131,6 +131,7 @@ def _preview_module_system(request, descriptor): ...@@ -131,6 +131,7 @@ def _preview_module_system(request, descriptor):
# get_user_role accepts a location or a CourseLocator. # get_user_role accepts a location or a CourseLocator.
# If descriptor.location is a CourseLocator, course_id is unused. # If descriptor.location is a CourseLocator, course_id is unused.
get_user_role=lambda: get_user_role(request.user, descriptor.location, course_id), get_user_role=lambda: get_user_role(request.user, descriptor.location, course_id),
descriptor_runtime=descriptor.runtime,
) )
...@@ -158,6 +159,6 @@ def get_preview_fragment(request, descriptor): ...@@ -158,6 +159,6 @@ def get_preview_fragment(request, descriptor):
try: try:
fragment = module.render("student_view") fragment = module.render("student_view")
except Exception as exc: # pylint: disable=W0703 except Exception as exc: # pylint: disable=W0703
log.debug("Unable to render student_view for %r", module, exc_info=True) log.warning("Unable to render student_view for %r", module, exc_info=True)
fragment = Fragment(render_to_string('html_error.html', {'message': str(exc)})) fragment = Fragment(render_to_string('html_error.html', {'message': str(exc)}))
return fragment return fragment
...@@ -3,7 +3,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) -> ...@@ -3,7 +3,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) ->
class PreviewRuntime.v1 extends XBlock.Runtime.v1 class PreviewRuntime.v1 extends XBlock.Runtime.v1
handlerUrl: (element, handlerName, suffix, query, thirdparty) -> handlerUrl: (element, handlerName, suffix, query, thirdparty) ->
uri = URI("/preview/xblock").segment($(@element).data('usage-id')) uri = URI("/preview/xblock").segment($(element).data('usage-id'))
.segment('handler') .segment('handler')
.segment(handlerName) .segment(handlerName)
if suffix? then uri.segment(suffix) if suffix? then uri.segment(suffix)
...@@ -14,7 +14,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) -> ...@@ -14,7 +14,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) ->
class StudioRuntime.v1 extends XBlock.Runtime.v1 class StudioRuntime.v1 extends XBlock.Runtime.v1
handlerUrl: (element, handlerName, suffix, query, thirdparty) -> handlerUrl: (element, handlerName, suffix, query, thirdparty) ->
uri = URI("/xblock").segment($(@element).data('usage-id')) uri = URI("/xblock").segment($(element).data('usage-id'))
.segment('handler') .segment('handler')
.segment(handlerName) .segment(handlerName)
if suffix? then uri.segment(suffix) if suffix? then uri.segment(suffix)
......
...@@ -78,6 +78,7 @@ def get_test_system(course_id=''): ...@@ -78,6 +78,7 @@ def get_test_system(course_id=''):
course_id=course_id, course_id=course_id,
error_descriptor_class=ErrorDescriptor, error_descriptor_class=ErrorDescriptor,
get_user_role=Mock(is_staff=False), get_user_role=Mock(is_staff=False),
descriptor_runtime=get_test_descriptor_system(),
) )
......
...@@ -1048,7 +1048,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs ...@@ -1048,7 +1048,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
""" """
def __init__( def __init__(
self, static_url, track_function, get_module, render_template, self, static_url, track_function, get_module, render_template,
replace_urls, user=None, filestore=None, replace_urls, descriptor_runtime, user=None, filestore=None,
debug=False, hostname="", xqueue=None, publish=None, node_path="", debug=False, hostname="", xqueue=None, publish=None, node_path="",
anonymous_student_id='', course_id=None, anonymous_student_id='', course_id=None,
open_ended_grading_interface=None, s3_interface=None, open_ended_grading_interface=None, s3_interface=None,
...@@ -1089,6 +1089,8 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs ...@@ -1089,6 +1089,8 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
that capa_module can use to fix up the static urls in that capa_module can use to fix up the static urls in
ajax results. ajax results.
descriptor_runtime - A `DescriptorSystem` to use for loading xblocks by id
anonymous_student_id - Used for tracking modules with student id anonymous_student_id - Used for tracking modules with student id
course_id - the course_id containing this module course_id - the course_id containing this module
...@@ -1148,6 +1150,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs ...@@ -1148,6 +1150,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
self.get_real_user = get_real_user self.get_real_user = get_real_user
self.get_user_role = get_user_role self.get_user_role = get_user_role
self.descriptor_runtime = descriptor_runtime
def get(self, attr): def get(self, attr):
""" provide uniform access to attributes (like etree).""" """ provide uniform access to attributes (like etree)."""
...@@ -1172,7 +1175,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs ...@@ -1172,7 +1175,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
return self.handler_url(self.xmodule_instance, 'xmodule_handler', '', '').rstrip('/?') return self.handler_url(self.xmodule_instance, 'xmodule_handler', '', '').rstrip('/?')
def get_block(self, block_id): def get_block(self, block_id):
raise NotImplementedError("XModules must use get_module to load other modules") return self.get_module(self.descriptor_runtime.get_block(block_id))
def resource_url(self, resource): def resource_url(self, resource):
raise NotImplementedError("edX Platform doesn't currently implement XBlock resource urls") raise NotImplementedError("edX Platform doesn't currently implement XBlock resource urls")
......
...@@ -31,8 +31,8 @@ describe "XBlock", -> ...@@ -31,8 +31,8 @@ describe "XBlock", ->
@missingInitBlock = XBlock.initializeBlock($('#missing-init')[0]) @missingInitBlock = XBlock.initializeBlock($('#missing-init')[0])
it "loads the right runtime version", -> it "loads the right runtime version", ->
expect(TestRuntime.vA).toHaveBeenCalledWith($('#vA')[0], @fakeChildren) expect(TestRuntime.vA).toHaveBeenCalledWith()
expect(TestRuntime.vZ).toHaveBeenCalledWith($('#vZ')[0], @fakeChildren) expect(TestRuntime.vZ).toHaveBeenCalledWith()
it "loads the right init function", -> it "loads the right init function", ->
expect(window.initFnA).toHaveBeenCalledWith(@runtimeA, $('#vA')[0]) expect(window.initFnA).toHaveBeenCalledWith(@runtimeA, $('#vA')[0])
......
...@@ -9,12 +9,13 @@ describe "XBlock.Runtime.v1", -> ...@@ -9,12 +9,13 @@ describe "XBlock.Runtime.v1", ->
] ]
@element = $('.xblock')[0] @element = $('.xblock')[0]
$(@element).prop('xblock_children', @children)
@runtime = new XBlock.Runtime.v1(@element, @children) @runtime = new XBlock.Runtime.v1(@element)
it "provides a list of children", -> it "provides a list of children", ->
expect(@runtime.children).toBe(@children) expect(@runtime.children(@element)).toBe(@children)
it "maps children by name", -> it "maps children by name", ->
expect(@runtime.childMap.childA).toBe(@children[0]) expect(@runtime.childMap(@element, 'childA')).toBe(@children[0])
expect(@runtime.childMap.childB).toBe(@children[1]) expect(@runtime.childMap(@element, 'childB')).toBe(@children[1])
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
runtime = $element.data("runtime-class") runtime = $element.data("runtime-class")
version = $element.data("runtime-version") version = $element.data("runtime-version")
initFnName = $element.data("init") initFnName = $element.data("init")
$element.prop('xblock_children', children)
if runtime? and version? and initFnName? if runtime? and version? and initFnName?
runtime = new window[runtime]["v#{version}"](element, children) runtime = new window[runtime]["v#{version}"]
initFn = window[initFnName] initFn = window[initFnName]
block = initFn(runtime, element) ? {} block = initFn(runtime, element) ? {}
else else
......
class XBlock.Runtime.v1 class XBlock.Runtime.v1
constructor: (@element, @children) -> children: (block) => $(block).prop('xblock_children')
@childMap = {} childMap: (block, childName) =>
$.each @children, (idx, child) => for child in @children(block)
@childMap[child.name] = child return child if child.name == childName
\ No newline at end of file
...@@ -4,7 +4,7 @@ Unit page in Studio ...@@ -4,7 +4,7 @@ Unit page in Studio
from bok_choy.page_object import PageObject from bok_choy.page_object import PageObject
from bok_choy.query import SubQuery from bok_choy.query import SubQuery
from bok_choy.promise import Promise, EmptyPromise, fulfill from bok_choy.promise import EmptyPromise, fulfill
from . import BASE_URL from . import BASE_URL
...@@ -24,20 +24,32 @@ class UnitPage(PageObject): ...@@ -24,20 +24,32 @@ class UnitPage(PageObject):
return "{}/unit/{}".format(BASE_URL, self.unit_locator) return "{}/unit/{}".format(BASE_URL, self.unit_locator)
def is_browser_on_page(self): def is_browser_on_page(self):
return self.is_css_present('body.view-unit') # Wait until all components have been loaded
return (
def component(self, title): self.is_css_present('body.view-unit') and
return Component(self.browser, self._locator(title)) len(self.q(css=Component.BODY_SELECTOR)) == len(self.q(css='{} .xblock-student_view'.format(Component.BODY_SELECTOR)))
)
def _locator(self, title):
def _check_func():
locators = self.q(css=Component.BODY_SELECTOR).filter(
SubQuery(css=Component.NAME_SELECTOR).filter(text=title)
).map(lambda el: el['data-locator']).results
return (len(locators) > 0, locators[0]) @property
def components(self):
"""
Return a list of components loaded on the unit page.
"""
return self.q(css=Component.BODY_SELECTOR).map(lambda el: Component(self.browser, el['data-locator'])).results
return fulfill(Promise(_check_func, "Found data locator for component")) def edit_draft(self):
"""
Started editing a draft of this unit.
"""
fulfill(EmptyPromise(
lambda: self.q(css='.create-draft').present,
'Wait for edit draft link to be present'
))
self.q(css='.create-draft').click()
fulfill(EmptyPromise(
lambda: self.q(css='.editing-draft-alert').present,
'Wait for draft mode to be activated'
))
class Component(PageObject): class Component(PageObject):
......
...@@ -51,6 +51,16 @@ class AcidView(PageObject): ...@@ -51,6 +51,16 @@ class AcidView(PageObject):
""" """
return self.test_passed('.document-ready-run') return self.test_passed('.document-ready-run')
@property
def child_tests_passed(self):
"""
Whether the tests of children passed
"""
return all([
self.test_passed('.child-counts-match'),
self.test_passed('.child-values-match')
])
def scope_passed(self, scope): def scope_passed(self, scope):
return all( return all(
self.test_passed('.scope-storage-test.scope-{} {}'.format(scope, test)) self.test_passed('.scope-storage-test.scope-{} {}'.format(scope, test))
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
E2E tests for the LMS. E2E tests for the LMS.
""" """
from unittest import skip from unittest import skip, expectedFailure
from bok_choy.web_app_test import WebAppTest from bok_choy.web_app_test import WebAppTest
from bok_choy.promise import EmptyPromise, fulfill_before, fulfill, Promise from bok_choy.promise import EmptyPromise, fulfill_before, fulfill, Promise
...@@ -292,8 +292,9 @@ class VideoTest(UniqueCourseTest): ...@@ -292,8 +292,9 @@ class VideoTest(UniqueCourseTest):
course_fix.add_children( course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('video', 'Video') XBlockFixtureDesc('vertical', 'Test Unit').add_children(
))).install() XBlockFixtureDesc('video', 'Video')
)))).install()
# Auto-auth register for the course # Auto-auth register for the course
...@@ -338,18 +339,48 @@ class VideoTest(UniqueCourseTest): ...@@ -338,18 +339,48 @@ class VideoTest(UniqueCourseTest):
self.assertGreaterEqual(self.video.duration, self.video.elapsed_time) self.assertGreaterEqual(self.video.duration, self.video.elapsed_time)
class XBlockAcidTest(UniqueCourseTest): class XBlockAcidBase(UniqueCourseTest):
""" """
Tests that verify that XBlock integration is working correctly Base class for tests that verify that XBlock integration is working correctly
""" """
__test__ = False
def setUp(self): def setUp(self):
""" """
Create a unique identifier for the course used in this test. Create a unique identifier for the course used in this test.
""" """
# Ensure that the superclass sets up # Ensure that the superclass sets up
super(XBlockAcidTest, self).setUp() super(XBlockAcidBase, self).setUp()
self.setup_fixtures()
AutoAuthPage(self.browser, course_id=self.course_id).visit()
self.course_info_page = CourseInfoPage(self.browser, self.course_id)
self.tab_nav = TabNavPage(self.browser)
def test_acid_block(self):
"""
Verify that all expected acid block tests pass in the lms.
"""
self.course_info_page.visit()
self.tab_nav.go_to_tab('Courseware')
acid_block = AcidView(self.browser, '.xblock-student_view[data-block-type=acid]')
self.assertTrue(acid_block.init_fn_passed)
self.assertTrue(acid_block.doc_ready_passed)
self.assertTrue(acid_block.child_tests_passed)
self.assertTrue(acid_block.scope_passed('user_state'))
class XBlockAcidNoChildTest(XBlockAcidBase):
"""
Tests of an AcidBlock with no children
"""
__test__ = True
def setup_fixtures(self):
course_fix = CourseFixture( course_fix = CourseFixture(
self.course_info['org'], self.course_info['org'],
self.course_info['number'], self.course_info['number'],
...@@ -360,24 +391,43 @@ class XBlockAcidTest(UniqueCourseTest): ...@@ -360,24 +391,43 @@ class XBlockAcidTest(UniqueCourseTest):
course_fix.add_children( course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('acid', 'Acid Block') XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc('acid', 'Acid Block')
)
) )
) )
).install() ).install()
AutoAuthPage(self.browser, course_id=self.course_id).visit()
self.course_info_page = CourseInfoPage(self.browser, self.course_id) class XBlockAcidChildTest(XBlockAcidBase):
self.tab_nav = TabNavPage(self.browser) """
Tests of an AcidBlock with children
"""
__test__ = True
self.course_info_page.visit() def setup_fixtures(self):
self.tab_nav.go_to_tab('Courseware') course_fix = CourseFixture(
self.course_info['org'],
self.course_info['number'],
self.course_info['run'],
self.course_info['display_name']
)
course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc('acid', 'Acid Block').add_children(
XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}),
XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}),
XBlockFixtureDesc('html', 'Html Child', data="<html>Contents</html>"),
)
)
)
)
).install()
# This will fail until we fix support of children in pure XBlocks
@expectedFailure
def test_acid_block(self): def test_acid_block(self):
""" super(XBlockAcidChildTest, self).test_acid_block()
Verify that all expected acid block tests pass in the lms.
"""
acid_block = AcidView(self.browser, '.xblock-student_view[data-block-type=acid]')
self.assertTrue(acid_block.init_fn_passed)
self.assertTrue(acid_block.doc_ready_passed)
self.assertTrue(acid_block.scope_passed('user_state'))
""" """
Acceptance tests for Studio. Acceptance tests for Studio.
""" """
from unittest import expectedFailure
from bok_choy.web_app_test import WebAppTest from bok_choy.web_app_test import WebAppTest
from ..pages.studio.asset_index import AssetIndexPage from ..pages.studio.asset_index import AssetIndexPage
...@@ -110,17 +112,18 @@ class CoursePagesTest(UniqueCourseTest): ...@@ -110,17 +112,18 @@ class CoursePagesTest(UniqueCourseTest):
page.visit() page.visit()
class XBlockAcidTest(WebAppTest): class XBlockAcidBase(WebAppTest):
""" """
Tests that verify that XBlock integration is working correctly Base class for tests that verify that XBlock integration is working correctly
""" """
__test__ = False
def setUp(self): def setUp(self):
""" """
Create a unique identifier for the course used in this test. Create a unique identifier for the course used in this test.
""" """
# Ensure that the superclass sets up # Ensure that the superclass sets up
super(XBlockAcidTest, self).setUp() super(XBlockAcidBase, self).setUp()
# Define a unique course identifier # Define a unique course identifier
self.course_info = { self.course_info = {
...@@ -140,6 +143,50 @@ class XBlockAcidTest(WebAppTest): ...@@ -140,6 +143,50 @@ class XBlockAcidTest(WebAppTest):
self.course_id = '{org}.{number}.{run}'.format(**self.course_info) self.course_id = '{org}.{number}.{run}'.format(**self.course_info)
self.setup_fixtures()
self.auth_page.visit()
def test_acid_block_preview(self):
"""
Verify that all expected acid block tests pass in studio preview
"""
self.outline.visit()
unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to()
acid_block = AcidView(self.browser, unit.components[0].preview_selector)
self.assertTrue(acid_block.init_fn_passed)
self.assertTrue(acid_block.doc_ready_passed)
self.assertTrue(acid_block.child_tests_passed)
self.assertTrue(acid_block.scope_passed('user_state'))
def test_acid_block_editor(self):
"""
Verify that all expected acid block tests pass in studio preview
"""
self.outline.visit()
unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to()
unit.edit_draft()
acid_block = AcidView(self.browser, unit.components[0].edit().editor_selector)
self.assertTrue(acid_block.init_fn_passed)
self.assertTrue(acid_block.doc_ready_passed)
self.assertTrue(acid_block.child_tests_passed)
self.assertTrue(acid_block.scope_passed('content'))
self.assertTrue(acid_block.scope_passed('settings'))
class XBlockAcidNoChildTest(XBlockAcidBase):
"""
Tests of an AcidBlock with no children
"""
__test__ = True
def setup_fixtures(self):
course_fix = CourseFixture( course_fix = CourseFixture(
self.course_info['org'], self.course_info['org'],
self.course_info['number'], self.course_info['number'],
...@@ -157,27 +204,42 @@ class XBlockAcidTest(WebAppTest): ...@@ -157,27 +204,42 @@ class XBlockAcidTest(WebAppTest):
) )
).install() ).install()
self.auth_page.visit()
self.outline.visit() class XBlockAcidChildTest(XBlockAcidBase):
unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to() """
self.acid_component = unit.component('Acid Block') Tests of an AcidBlock with children
"""
__test__ = True
def setup_fixtures(self):
course_fix = CourseFixture(
self.course_info['org'],
self.course_info['number'],
self.course_info['run'],
self.course_info['display_name']
)
course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc('acid', 'Acid Block').add_children(
XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}),
XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}),
XBlockFixtureDesc('html', 'Html Child', data="<html>Contents</html>"),
)
)
)
)
).install()
# This will fail until we fix support of children in pure XBlocks
@expectedFailure
def test_acid_block_preview(self): def test_acid_block_preview(self):
""" super(XBlockAcidChildTest, self).test_acid_block_preview()
Verify that all expected acid block tests pass in studio preview
"""
acid_block = AcidView(self.browser, self.acid_component.preview_selector)
self.assertTrue(acid_block.init_fn_passed)
self.assertTrue(acid_block.doc_ready_passed)
self.assertTrue(acid_block.scope_passed('user_state'))
# This will fail until we fix support of children in pure XBlocks
@expectedFailure
def test_acid_block_editor(self): def test_acid_block_editor(self):
""" super(XBlockAcidChildTest, self).test_acid_block_editor()
Verify that all expected acid block tests pass in studio preview
"""
acid_block = AcidView(self.browser, self.acid_component.edit().editor_selector)
self.assertTrue(acid_block.init_fn_passed)
self.assertTrue(acid_block.doc_ready_passed)
self.assertTrue(acid_block.scope_passed('content'))
self.assertTrue(acid_block.scope_passed('settings'))
...@@ -227,7 +227,6 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours ...@@ -227,7 +227,6 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
return None return None
student_data = KvsFieldData(DjangoKeyValueStore(field_data_cache)) student_data = KvsFieldData(DjangoKeyValueStore(field_data_cache))
descriptor._field_data = LmsFieldData(descriptor._field_data, student_data)
def make_xqueue_callback(dispatch='score_update'): def make_xqueue_callback(dispatch='score_update'):
...@@ -433,6 +432,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours ...@@ -433,6 +432,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
'i18n': ModuleI18nService(), 'i18n': ModuleI18nService(),
}, },
get_user_role=lambda: get_user_role(user, course_id), get_user_role=lambda: get_user_role(user, course_id),
descriptor_runtime=descriptor.runtime,
) )
# pass position specified in URL to module through ModuleSystem # pass position specified in URL to module through ModuleSystem
...@@ -451,8 +451,8 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours ...@@ -451,8 +451,8 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
else: else:
system.error_descriptor_class = NonStaffErrorDescriptor system.error_descriptor_class = NonStaffErrorDescriptor
descriptor.xmodule_runtime = system descriptor.bind_for_student(system, LmsFieldData(descriptor._field_data, student_data)) # pylint: disable=protected-access
descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id) descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id) # pylint: disable=protected-access
return descriptor return descriptor
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Test for lms courseware app, module render unit Test for lms courseware app, module render unit
""" """
from ddt import ddt, data from ddt import ddt, data
from functools import partial
from mock import MagicMock, patch, Mock from mock import MagicMock, patch, Mock
import json import json
...@@ -657,6 +658,9 @@ class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -657,6 +658,9 @@ class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase):
), ),
scope_ids=Mock(spec=ScopeIds), scope_ids=Mock(spec=ScopeIds),
) )
# Use the xblock_class's bind_for_student method
descriptor.bind_for_student = partial(xblock_class.bind_for_student, descriptor)
if hasattr(xblock_class, 'module_class'): if hasattr(xblock_class, 'module_class'):
descriptor.module_class = xblock_class.module_class descriptor.module_class = xblock_class.module_class
......
...@@ -69,6 +69,7 @@ def peer_grading_notifications(course, user): ...@@ -69,6 +69,7 @@ def peer_grading_notifications(course, user):
get_module=None, get_module=None,
render_template=render_to_string, render_template=render_to_string,
replace_urls=None, replace_urls=None,
descriptor_runtime=None,
) )
peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, system) peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
pending_grading = False pending_grading = False
...@@ -129,6 +130,7 @@ def combined_notifications(course, user): ...@@ -129,6 +130,7 @@ def combined_notifications(course, user):
get_module=None, get_module=None,
render_template=render_to_string, render_template=render_to_string,
replace_urls=None, replace_urls=None,
descriptor_runtime=None,
) )
#Initialize controller query service using our mock system #Initialize controller query service using our mock system
controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system) controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
......
...@@ -83,6 +83,7 @@ class StaffGradingService(GradingService): ...@@ -83,6 +83,7 @@ class StaffGradingService(GradingService):
get_module=None, get_module=None,
render_template=render_to_string, render_template=render_to_string,
replace_urls=None, replace_urls=None,
descriptor_runtime=None,
) )
super(StaffGradingService, self).__init__(config) super(StaffGradingService, self).__init__(config)
self.url = config['url'] + config['staff_grading'] self.url = config['url'] + config['staff_grading']
......
...@@ -285,6 +285,7 @@ class TestPeerGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -285,6 +285,7 @@ class TestPeerGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase):
open_ended_grading_interface=test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, open_ended_grading_interface=test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
mixins=settings.XBLOCK_MIXINS, mixins=settings.XBLOCK_MIXINS,
error_descriptor_class=ErrorDescriptor, error_descriptor_class=ErrorDescriptor,
descriptor_runtime=None,
) )
self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system, field_data, ScopeIds(None, None, None, None)) self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system, field_data, ScopeIds(None, None, None, None))
self.descriptor.xmodule_runtime = self.system self.descriptor.xmodule_runtime = self.system
......
...@@ -33,6 +33,7 @@ SYSTEM = LmsModuleSystem( ...@@ -33,6 +33,7 @@ SYSTEM = LmsModuleSystem(
get_module=None, get_module=None,
render_template=render_to_string, render_template=render_to_string,
replace_urls=None, replace_urls=None,
descriptor_runtime=None,
) )
......
...@@ -48,6 +48,7 @@ class TestHandlerUrl(TestCase): ...@@ -48,6 +48,7 @@ class TestHandlerUrl(TestCase):
render_template=Mock(), render_template=Mock(),
replace_urls=str, replace_urls=str,
course_id=self.course_id, course_id=self.course_id,
descriptor_runtime=Mock(),
) )
def test_trailing_characters(self): def test_trailing_characters(self):
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
class LmsRuntime.v1 extends XBlock.Runtime.v1 class LmsRuntime.v1 extends XBlock.Runtime.v1
handlerUrl: (element, handlerName, suffix, query, thirdparty) -> handlerUrl: (element, handlerName, suffix, query, thirdparty) ->
courseId = $(@element).data("course-id") courseId = $(element).data("course-id")
usageId = $(@element).data("usage-id") usageId = $(element).data("usage-id")
handlerAuth = if thirdparty then "handler_noauth" else "handler" handlerAuth = if thirdparty then "handler_noauth" else "handler"
uri = URI('/courses').segment(courseId) uri = URI('/courses').segment(courseId)
......
...@@ -21,6 +21,6 @@ ...@@ -21,6 +21,6 @@
-e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool -e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool
-e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle -e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle
-e git+https://github.com/edx/event-tracking.git@f0211d702d#egg=event-tracking -e git+https://github.com/edx/event-tracking.git@f0211d702d#egg=event-tracking
-e git+https://github.com/edx/bok-choy.git@v0.2.1#egg=bok_choy -e git+https://github.com/edx/bok-choy.git@62de7b576a08f36cde5b030c52bccb1a2f3f8df1#egg=bok_choy
-e git+https://github.com/edx-solutions/django-splash.git@15bf143b15714e22fc451ff1b0f8a7a2a9483172#egg=django-splash -e git+https://github.com/edx-solutions/django-splash.git@15bf143b15714e22fc451ff1b0f8a7a2a9483172#egg=django-splash
-e git+https://github.com/edx/acid-block.git@aa95a3c#egg=acid-xblock -e git+https://github.com/edx/acid-block.git@9c832513f0c01f79227bea894fba11c66fe4c08c#egg=acid-xblock
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment