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.
This commit is contained in:
Calen Pennington
2014-02-13 09:53:32 -05:00
parent 3093efc889
commit dbc99ef8ad
21 changed files with 228 additions and 77 deletions

View File

@@ -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):

View File

@@ -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))

View File

@@ -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()

View File

@@ -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()