Merge pull request #2602 from cpennington/xblock-acid-child-tests
Add tests of the frontend children api using the AcidXBlock
This commit is contained in:
@@ -316,9 +316,18 @@ def _save_item(request, usage_loc, item_location, data=None, children=None, meta
|
||||
# Make public after updating the xblock, in case the caller asked
|
||||
# for both an update and a publish.
|
||||
if publish and publish == 'make_public':
|
||||
def _publish(block):
|
||||
# This is super gross, but prevents us from publishing something that
|
||||
# we shouldn't. Ideally, all modulestores would have a consistant
|
||||
# interface for publishing. However, as of now, only the DraftMongoModulestore
|
||||
# does, so we have to check for the attribute explicitly.
|
||||
store = get_modulestore(block.location)
|
||||
if hasattr(store, 'publish'):
|
||||
store.publish(block.location, request.user.id)
|
||||
|
||||
_xmodule_recurse(
|
||||
existing_item,
|
||||
lambda i: modulestore().publish(i.location, request.user.id)
|
||||
_publish
|
||||
)
|
||||
|
||||
# Note that children aren't being returned until we have a use case.
|
||||
|
||||
@@ -131,6 +131,7 @@ def _preview_module_system(request, descriptor):
|
||||
# get_user_role accepts a location or a CourseLocator.
|
||||
# If descriptor.location is a CourseLocator, course_id is unused.
|
||||
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):
|
||||
try:
|
||||
fragment = module.render("student_view")
|
||||
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)}))
|
||||
return fragment
|
||||
|
||||
@@ -3,7 +3,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) ->
|
||||
|
||||
class PreviewRuntime.v1 extends XBlock.Runtime.v1
|
||||
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(handlerName)
|
||||
if suffix? then uri.segment(suffix)
|
||||
@@ -14,7 +14,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) ->
|
||||
|
||||
class StudioRuntime.v1 extends XBlock.Runtime.v1
|
||||
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(handlerName)
|
||||
if suffix? then uri.segment(suffix)
|
||||
|
||||
@@ -78,6 +78,7 @@ def get_test_system(course_id=''):
|
||||
course_id=course_id,
|
||||
error_descriptor_class=ErrorDescriptor,
|
||||
get_user_role=Mock(is_staff=False),
|
||||
descriptor_runtime=get_test_descriptor_system(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1048,7 +1048,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
|
||||
"""
|
||||
def __init__(
|
||||
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="",
|
||||
anonymous_student_id='', course_id=None,
|
||||
open_ended_grading_interface=None, s3_interface=None,
|
||||
@@ -1089,6 +1089,8 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
|
||||
that capa_module can use to fix up the static urls in
|
||||
ajax results.
|
||||
|
||||
descriptor_runtime - A `DescriptorSystem` to use for loading xblocks by id
|
||||
|
||||
anonymous_student_id - Used for tracking modules with student id
|
||||
|
||||
course_id - the course_id containing this module
|
||||
@@ -1148,6 +1150,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
|
||||
self.get_real_user = get_real_user
|
||||
|
||||
self.get_user_role = get_user_role
|
||||
self.descriptor_runtime = descriptor_runtime
|
||||
|
||||
def get(self, attr):
|
||||
""" provide uniform access to attributes (like etree)."""
|
||||
@@ -1172,7 +1175,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
|
||||
return self.handler_url(self.xmodule_instance, 'xmodule_handler', '', '').rstrip('/?')
|
||||
|
||||
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):
|
||||
raise NotImplementedError("edX Platform doesn't currently implement XBlock resource urls")
|
||||
|
||||
@@ -31,8 +31,8 @@ describe "XBlock", ->
|
||||
@missingInitBlock = XBlock.initializeBlock($('#missing-init')[0])
|
||||
|
||||
it "loads the right runtime version", ->
|
||||
expect(TestRuntime.vA).toHaveBeenCalledWith($('#vA')[0], @fakeChildren)
|
||||
expect(TestRuntime.vZ).toHaveBeenCalledWith($('#vZ')[0], @fakeChildren)
|
||||
expect(TestRuntime.vA).toHaveBeenCalledWith()
|
||||
expect(TestRuntime.vZ).toHaveBeenCalledWith()
|
||||
|
||||
it "loads the right init function", ->
|
||||
expect(window.initFnA).toHaveBeenCalledWith(@runtimeA, $('#vA')[0])
|
||||
|
||||
@@ -9,12 +9,13 @@ describe "XBlock.Runtime.v1", ->
|
||||
]
|
||||
|
||||
@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", ->
|
||||
expect(@runtime.children).toBe(@children)
|
||||
expect(@runtime.children(@element)).toBe(@children)
|
||||
|
||||
it "maps children by name", ->
|
||||
expect(@runtime.childMap.childA).toBe(@children[0])
|
||||
expect(@runtime.childMap.childB).toBe(@children[1])
|
||||
expect(@runtime.childMap(@element, 'childA')).toBe(@children[0])
|
||||
expect(@runtime.childMap(@element, 'childB')).toBe(@children[1])
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
runtime = $element.data("runtime-class")
|
||||
version = $element.data("runtime-version")
|
||||
initFnName = $element.data("init")
|
||||
$element.prop('xblock_children', children)
|
||||
if runtime? and version? and initFnName?
|
||||
runtime = new window[runtime]["v#{version}"](element, children)
|
||||
runtime = new window[runtime]["v#{version}"]
|
||||
initFn = window[initFnName]
|
||||
block = initFn(runtime, element) ? {}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class XBlock.Runtime.v1
|
||||
constructor: (@element, @children) ->
|
||||
@childMap = {}
|
||||
$.each @children, (idx, child) =>
|
||||
@childMap[child.name] = child
|
||||
children: (block) => $(block).prop('xblock_children')
|
||||
childMap: (block, childName) =>
|
||||
for child in @children(block)
|
||||
return child if child.name == childName
|
||||
@@ -95,31 +95,20 @@ class XBlockFixtureDesc(object):
|
||||
self.children.extend(args)
|
||||
return self
|
||||
|
||||
def serialize(self, parent_loc=None):
|
||||
def serialize(self):
|
||||
"""
|
||||
Return a JSON representation of the XBlock, suitable
|
||||
for sending as POST data to /xblock
|
||||
|
||||
XBlocks are always set to public visibility.
|
||||
"""
|
||||
payload = {
|
||||
'category': self.category,
|
||||
return json.dumps({
|
||||
'display_name': self.display_name,
|
||||
'data': self.data,
|
||||
'metadata': self.metadata,
|
||||
'grader_type': self.grader_type,
|
||||
'graderType': self.grader_type,
|
||||
'publish': self.publish
|
||||
}
|
||||
|
||||
# Need to handle detached categories differently, since they are not published
|
||||
# This may change in the future.
|
||||
if self.category in ['static_tab']:
|
||||
del payload['publish']
|
||||
|
||||
if parent_loc is not None:
|
||||
payload['parent_locator'] = parent_loc
|
||||
|
||||
return json.dumps(payload)
|
||||
})
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
@@ -395,15 +384,25 @@ class CourseFixture(StudioApiFixture):
|
||||
loc = self._create_xblock(parent_loc, desc)
|
||||
self._create_xblock_children(loc, desc.children)
|
||||
|
||||
self._publish_xblock(parent_loc)
|
||||
|
||||
def _create_xblock(self, parent_loc, xblock_desc):
|
||||
"""
|
||||
Create an XBlock with `parent_loc` (the location of the parent block)
|
||||
and `xblock_desc` (an `XBlockFixtureDesc` instance).
|
||||
"""
|
||||
create_payload = {
|
||||
'category': xblock_desc.category,
|
||||
'display_name': xblock_desc.display_name,
|
||||
}
|
||||
|
||||
if parent_loc is not None:
|
||||
create_payload['parent_locator'] = parent_loc
|
||||
|
||||
# Create the new XBlock
|
||||
response = self.session.post(
|
||||
STUDIO_BASE_URL + '/xblock',
|
||||
data=xblock_desc.serialize(parent_loc=parent_loc),
|
||||
data=json.dumps(create_payload),
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
@@ -417,24 +416,34 @@ class CourseFixture(StudioApiFixture):
|
||||
except ValueError:
|
||||
raise CourseFixtureError("Could not decode JSON from '{0}'".format(response.content))
|
||||
|
||||
if loc is not None:
|
||||
|
||||
# Configure the XBlock
|
||||
response = self.session.post(
|
||||
STUDIO_BASE_URL + '/xblock/' + loc,
|
||||
data=xblock_desc.serialize(),
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
if response.ok:
|
||||
return loc
|
||||
else:
|
||||
raise CourseFixtureError(
|
||||
"Could not update {0}. Status code: {1}".format(
|
||||
xblock_desc, response.status_code))
|
||||
# Configure the XBlock
|
||||
response = self.session.post(
|
||||
STUDIO_BASE_URL + '/xblock/' + loc,
|
||||
data=xblock_desc.serialize(),
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
if response.ok:
|
||||
return loc
|
||||
else:
|
||||
raise CourseFixtureError("Could not retrieve location of {0}".format(xblock_desc))
|
||||
raise CourseFixtureError(
|
||||
"Could not update {0}. Status code: {1}".format(
|
||||
xblock_desc, response.status_code))
|
||||
|
||||
def _publish_xblock(self, locator):
|
||||
"""
|
||||
Publish the xblock at `locator`.
|
||||
"""
|
||||
# Create the new XBlock
|
||||
response = self.session.put(
|
||||
"{}/xblock/{}".format(STUDIO_BASE_URL, locator),
|
||||
data=json.dumps({'publish': 'make_public'}),
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
if not response.ok:
|
||||
msg = "Could not publish {}. Status was {}".format(locator, response.status_code)
|
||||
raise CourseFixtureError(msg)
|
||||
|
||||
def _encode_post_dict(self, post_dict):
|
||||
"""
|
||||
|
||||
@@ -4,7 +4,7 @@ Unit page in Studio
|
||||
|
||||
from bok_choy.page_object import PageObject
|
||||
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
|
||||
|
||||
@@ -24,20 +24,32 @@ class UnitPage(PageObject):
|
||||
return "{}/unit/{}".format(BASE_URL, self.unit_locator)
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.is_css_present('body.view-unit')
|
||||
# Wait until all components have been loaded
|
||||
return (
|
||||
self.is_css_present('body.view-unit') and
|
||||
len(self.q(css=Component.BODY_SELECTOR)) == len(self.q(css='{} .xblock-student_view'.format(Component.BODY_SELECTOR)))
|
||||
)
|
||||
|
||||
def component(self, title):
|
||||
return Component(self.browser, self._locator(title))
|
||||
@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
|
||||
|
||||
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])
|
||||
|
||||
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):
|
||||
|
||||
@@ -51,6 +51,16 @@ class AcidView(PageObject):
|
||||
"""
|
||||
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):
|
||||
return all(
|
||||
self.test_passed('.scope-storage-test.scope-{} {}'.format(scope, test))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
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.promise import EmptyPromise, fulfill_before, fulfill, Promise
|
||||
@@ -292,8 +292,9 @@ class VideoTest(UniqueCourseTest):
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('video', 'Video')
|
||||
))).install()
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('video', 'Video')
|
||||
)))).install()
|
||||
|
||||
|
||||
# Auto-auth register for the course
|
||||
@@ -338,18 +339,48 @@ class VideoTest(UniqueCourseTest):
|
||||
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):
|
||||
"""
|
||||
Create a unique identifier for the course used in this test.
|
||||
"""
|
||||
# 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(
|
||||
self.course_info['org'],
|
||||
self.course_info['number'],
|
||||
@@ -360,24 +391,43 @@ class XBlockAcidTest(UniqueCourseTest):
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('acid', 'Acid Block')
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('acid', 'Acid Block')
|
||||
)
|
||||
)
|
||||
)
|
||||
).install()
|
||||
|
||||
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)
|
||||
class XBlockAcidChildTest(XBlockAcidBase):
|
||||
"""
|
||||
Tests of an AcidBlock with children
|
||||
"""
|
||||
__test__ = True
|
||||
|
||||
self.course_info_page.visit()
|
||||
self.tab_nav.go_to_tab('Courseware')
|
||||
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(self):
|
||||
"""
|
||||
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'))
|
||||
super(XBlockAcidChildTest, self).test_acid_block()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""
|
||||
Acceptance tests for Studio.
|
||||
"""
|
||||
from unittest import expectedFailure
|
||||
|
||||
from bok_choy.web_app_test import WebAppTest
|
||||
|
||||
from ..pages.studio.asset_index import AssetIndexPage
|
||||
@@ -110,17 +112,18 @@ class CoursePagesTest(UniqueCourseTest):
|
||||
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):
|
||||
"""
|
||||
Create a unique identifier for the course used in this test.
|
||||
"""
|
||||
# Ensure that the superclass sets up
|
||||
super(XBlockAcidTest, self).setUp()
|
||||
super(XBlockAcidBase, self).setUp()
|
||||
|
||||
# Define a unique course identifier
|
||||
self.course_info = {
|
||||
@@ -140,6 +143,50 @@ class XBlockAcidTest(WebAppTest):
|
||||
|
||||
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(
|
||||
self.course_info['org'],
|
||||
self.course_info['number'],
|
||||
@@ -157,27 +204,42 @@ class XBlockAcidTest(WebAppTest):
|
||||
)
|
||||
).install()
|
||||
|
||||
self.auth_page.visit()
|
||||
|
||||
self.outline.visit()
|
||||
unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to()
|
||||
self.acid_component = unit.component('Acid Block')
|
||||
class XBlockAcidChildTest(XBlockAcidBase):
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
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'))
|
||||
super(XBlockAcidChildTest, self).test_acid_block_preview()
|
||||
|
||||
# This will fail until we fix support of children in pure XBlocks
|
||||
@expectedFailure
|
||||
def test_acid_block_editor(self):
|
||||
"""
|
||||
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'))
|
||||
super(XBlockAcidChildTest, self).test_acid_block_editor()
|
||||
|
||||
@@ -227,7 +227,6 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
return None
|
||||
|
||||
student_data = KvsFieldData(DjangoKeyValueStore(field_data_cache))
|
||||
descriptor._field_data = LmsFieldData(descriptor._field_data, student_data)
|
||||
|
||||
|
||||
def make_xqueue_callback(dispatch='score_update'):
|
||||
@@ -433,6 +432,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
'i18n': ModuleI18nService(),
|
||||
},
|
||||
get_user_role=lambda: get_user_role(user, course_id),
|
||||
descriptor_runtime=descriptor.runtime,
|
||||
)
|
||||
|
||||
# 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
|
||||
else:
|
||||
system.error_descriptor_class = NonStaffErrorDescriptor
|
||||
|
||||
descriptor.xmodule_runtime = system
|
||||
descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id)
|
||||
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) # pylint: disable=protected-access
|
||||
return descriptor
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Test for lms courseware app, module render unit
|
||||
"""
|
||||
from ddt import ddt, data
|
||||
from functools import partial
|
||||
from mock import MagicMock, patch, Mock
|
||||
import json
|
||||
|
||||
@@ -657,6 +658,9 @@ class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
),
|
||||
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'):
|
||||
descriptor.module_class = xblock_class.module_class
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ def peer_grading_notifications(course, user):
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
descriptor_runtime=None,
|
||||
)
|
||||
peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
|
||||
pending_grading = False
|
||||
@@ -129,6 +130,7 @@ def combined_notifications(course, user):
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
descriptor_runtime=None,
|
||||
)
|
||||
#Initialize controller query service using our mock system
|
||||
controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
|
||||
|
||||
@@ -83,6 +83,7 @@ class StaffGradingService(GradingService):
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
descriptor_runtime=None,
|
||||
)
|
||||
super(StaffGradingService, self).__init__(config)
|
||||
self.url = config['url'] + config['staff_grading']
|
||||
|
||||
@@ -285,6 +285,7 @@ class TestPeerGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
open_ended_grading_interface=test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
|
||||
mixins=settings.XBLOCK_MIXINS,
|
||||
error_descriptor_class=ErrorDescriptor,
|
||||
descriptor_runtime=None,
|
||||
)
|
||||
self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system, field_data, ScopeIds(None, None, None, None))
|
||||
self.descriptor.xmodule_runtime = self.system
|
||||
|
||||
@@ -33,6 +33,7 @@ SYSTEM = LmsModuleSystem(
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
descriptor_runtime=None,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class TestHandlerUrl(TestCase):
|
||||
render_template=Mock(),
|
||||
replace_urls=str,
|
||||
course_id=self.course_id,
|
||||
descriptor_runtime=Mock(),
|
||||
)
|
||||
|
||||
def test_trailing_characters(self):
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
class LmsRuntime.v1 extends XBlock.Runtime.v1
|
||||
handlerUrl: (element, handlerName, suffix, query, thirdparty) ->
|
||||
courseId = $(@element).data("course-id")
|
||||
usageId = $(@element).data("usage-id")
|
||||
courseId = $(element).data("course-id")
|
||||
usageId = $(element).data("usage-id")
|
||||
handlerAuth = if thirdparty then "handler_noauth" else "handler"
|
||||
|
||||
uri = URI('/courses').segment(courseId)
|
||||
|
||||
@@ -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/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/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/acid-block.git@aa95a3c#egg=acid-xblock
|
||||
-e git+https://github.com/edx/acid-block.git@9c832513f0c01f79227bea894fba11c66fe4c08c#egg=acid-xblock
|
||||
|
||||
Reference in New Issue
Block a user