Commit 2b45e10f by E. Kolpakov

Bok choy acceptance tests

parent e06b6fea
...@@ -35,8 +35,10 @@ def enum(**enums): ...@@ -35,8 +35,10 @@ def enum(**enums):
def _get_capa_types(): def _get_capa_types():
"""
Gets capa types tags and labels
"""
capa_types = { capa_types = {
ANY_CAPA_TYPE_VALUE: _('Any Type'),
'annotationinput': _('Annotation'), 'annotationinput': _('Annotation'),
'checkboxgroup': _('Checkbox Group'), 'checkboxgroup': _('Checkbox Group'),
'checkboxtextgroup': _('Checkbox Text Group'), 'checkboxtextgroup': _('Checkbox Text Group'),
...@@ -54,7 +56,7 @@ def _get_capa_types(): ...@@ -54,7 +56,7 @@ def _get_capa_types():
'javascriptinput': _('Javascript Input'), 'javascriptinput': _('Javascript Input'),
'jsinput': _('JS Input'), 'jsinput': _('JS Input'),
'matlabinput': _('Matlab'), 'matlabinput': _('Matlab'),
'optioninput': _('Select option'), 'optioninput': _('Select Option'),
'radiogroup': _('Radio Group'), 'radiogroup': _('Radio Group'),
'radiotextgroup': _('Radio Text Group'), 'radiotextgroup': _('Radio Text Group'),
'schematic': _('Schematic'), 'schematic': _('Schematic'),
...@@ -63,7 +65,7 @@ def _get_capa_types(): ...@@ -63,7 +65,7 @@ def _get_capa_types():
'vsepr_input': _('VSEPR'), 'vsepr_input': _('VSEPR'),
} }
return sorted([ return [{'value': ANY_CAPA_TYPE_VALUE, 'display_name': _('Any Type')}] + sorted([
{'value': capa_type, 'display_name': caption} {'value': capa_type, 'display_name': caption}
for capa_type, caption in capa_types.items() for capa_type, caption in capa_types.items()
], key=lambda item: item.get('display_name')) ], key=lambda item: item.get('display_name'))
...@@ -221,6 +223,9 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule): ...@@ -221,6 +223,9 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule):
any particular student. any particular student.
""" """
def _filter_children(self, child_locator): def _filter_children(self, child_locator):
"""
Filters children by CAPA problem type, if configured
"""
if self.capa_type == ANY_CAPA_TYPE_VALUE: if self.capa_type == ANY_CAPA_TYPE_VALUE:
return True return True
...@@ -234,7 +239,6 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule): ...@@ -234,7 +239,6 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule):
return any(self.capa_type in capa_input.tags for capa_input in block.lcp.inputs.values()) return any(self.capa_type in capa_input.tags for capa_input in block.lcp.inputs.values())
def selected_children(self): def selected_children(self):
""" """
Returns a set() of block_ids indicating which of the possible children Returns a set() of block_ids indicating which of the possible children
...@@ -427,8 +431,8 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe ...@@ -427,8 +431,8 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe
If source_libraries has been edited, refresh_children automatically. If source_libraries has been edited, refresh_children automatically.
""" """
old_source_libraries = LibraryList().from_json(old_metadata.get('source_libraries', [])) old_source_libraries = LibraryList().from_json(old_metadata.get('source_libraries', []))
if (set(old_source_libraries) != set(self.source_libraries) or if set(old_source_libraries) != set(self.source_libraries) or \
old_metadata.get('capa_type', ANY_CAPA_TYPE_VALUE) != self.capa_type): old_metadata.get('capa_type', ANY_CAPA_TYPE_VALUE) != self.capa_type:
try: try:
self.refresh_children(None, None, update_db=False) # update_db=False since update_item() is about to be called anyways self.refresh_children(None, None, update_db=False) # update_db=False since update_item() is about to be called anyways
except ValueError: except ValueError:
......
...@@ -16,6 +16,9 @@ class LibraryContentXBlockWrapper(PageObject): ...@@ -16,6 +16,9 @@ class LibraryContentXBlockWrapper(PageObject):
self.locator = locator self.locator = locator
def is_browser_on_page(self): def is_browser_on_page(self):
"""
Checks if page is opened
"""
return self.q(css='{}[data-id="{}"]'.format(self.BODY_SELECTOR, self.locator)).present return self.q(css='{}[data-id="{}"]'.format(self.BODY_SELECTOR, self.locator)).present
def _bounded_selector(self, selector): def _bounded_selector(self, selector):
...@@ -35,3 +38,11 @@ class LibraryContentXBlockWrapper(PageObject): ...@@ -35,3 +38,11 @@ class LibraryContentXBlockWrapper(PageObject):
""" """
child_blocks = self.q(css=self._bounded_selector("div[data-id]")) child_blocks = self.q(css=self._bounded_selector("div[data-id]"))
return frozenset(child.text for child in child_blocks) return frozenset(child.text for child in child_blocks)
@property
def children_headers(self):
"""
Gets headers if all child XBlocks as list of strings
"""
child_blocks_headers = self.q(css=self._bounded_selector("div[data-id] h2.problem-header"))
return frozenset(child.text for child in child_blocks_headers)
...@@ -122,6 +122,7 @@ class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject): ...@@ -122,6 +122,7 @@ class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject):
LIBRARY_LABEL = "Libraries" LIBRARY_LABEL = "Libraries"
COUNT_LABEL = "Count" COUNT_LABEL = "Count"
SCORED_LABEL = "Scored" SCORED_LABEL = "Scored"
PROBLEM_TYPE_LABEL = "Problem Type"
def is_browser_on_page(self): def is_browser_on_page(self):
""" """
...@@ -196,6 +197,24 @@ class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject): ...@@ -196,6 +197,24 @@ class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject):
scored_select.select_by_value(str(scored)) scored_select.select_by_value(str(scored))
EmptyPromise(lambda: self.scored == scored, "scored is updated in modal.").fulfill() EmptyPromise(lambda: self.scored == scored, "scored is updated in modal.").fulfill()
@property
def capa_type(self):
"""
Gets value of CAPA type select
"""
return self.get_metadata_input(self.PROBLEM_TYPE_LABEL).get_attribute('value')
@capa_type.setter
def capa_type(self, value):
"""
Sets value of CAPA type select
"""
select_element = self.get_metadata_input(self.PROBLEM_TYPE_LABEL)
select_element.click()
problem_type_select = Select(select_element)
problem_type_select.select_by_value(value)
EmptyPromise(lambda: self.capa_type == value, "problem type is updated in modal.").fulfill()
def _add_library_key(self): def _add_library_key(self):
""" """
Adds library key input Adds library key input
......
...@@ -19,22 +19,22 @@ SUBSECTION_NAME = 'Test Subsection' ...@@ -19,22 +19,22 @@ SUBSECTION_NAME = 'Test Subsection'
UNIT_NAME = 'Test Unit' UNIT_NAME = 'Test Unit'
@ddt.ddt class LibraryContentTestBase(UniqueCourseTest):
class LibraryContentTest(UniqueCourseTest): """ Base class for library content block tests """
"""
Test courseware.
"""
USERNAME = "STUDENT_TESTER" USERNAME = "STUDENT_TESTER"
EMAIL = "student101@example.com" EMAIL = "student101@example.com"
STAFF_USERNAME = "STAFF_TESTER" STAFF_USERNAME = "STAFF_TESTER"
STAFF_EMAIL = "staff101@example.com" STAFF_EMAIL = "staff101@example.com"
def populate_library_fixture(self, library_fixture):
pass
def setUp(self): def setUp(self):
""" """
Set up library, course and library content XBlock Set up library, course and library content XBlock
""" """
super(LibraryContentTest, self).setUp() super(LibraryContentTestBase, self).setUp()
self.courseware_page = CoursewarePage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id)
...@@ -46,11 +46,7 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -46,11 +46,7 @@ class LibraryContentTest(UniqueCourseTest):
) )
self.library_fixture = LibraryFixture('test_org', self.unique_id, 'Test Library {}'.format(self.unique_id)) self.library_fixture = LibraryFixture('test_org', self.unique_id, 'Test Library {}'.format(self.unique_id))
self.library_fixture.add_children( self.populate_library_fixture(self.library_fixture)
XBlockFixtureDesc("html", "Html1", data='html1'),
XBlockFixtureDesc("html", "Html2", data='html2'),
XBlockFixtureDesc("html", "Html3", data='html3'),
)
self.library_fixture.install() self.library_fixture.install()
self.library_info = self.library_fixture.library_info self.library_info = self.library_fixture.library_info
...@@ -83,7 +79,7 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -83,7 +79,7 @@ class LibraryContentTest(UniqueCourseTest):
self.course_fixture.install() self.course_fixture.install()
def _refresh_library_content_children(self, count=1): def _change_library_content_settings(self, count=1, capa_type=None):
""" """
Performs library block refresh in Studio, configuring it to show {count} children Performs library block refresh in Studio, configuring it to show {count} children
""" """
...@@ -91,6 +87,8 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -91,6 +87,8 @@ class LibraryContentTest(UniqueCourseTest):
library_container_block = StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(unit_page.xblocks[0]) library_container_block = StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(unit_page.xblocks[0])
modal = StudioLibraryContentXBlockEditModal(library_container_block.edit()) modal = StudioLibraryContentXBlockEditModal(library_container_block.edit())
modal.count = count modal.count = count
if capa_type is not None:
modal.capa_type = capa_type
library_container_block.save_settings() library_container_block.save_settings()
self._go_to_unit_page(change_login=False) self._go_to_unit_page(change_login=False)
unit_page.wait_for_page() unit_page.wait_for_page()
...@@ -124,6 +122,7 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -124,6 +122,7 @@ class LibraryContentTest(UniqueCourseTest):
block_id = block_id if block_id is not None else self.lib_block.locator block_id = block_id if block_id is not None else self.lib_block.locator
#pylint: disable=attribute-defined-outside-init #pylint: disable=attribute-defined-outside-init
self.library_content_page = LibraryContentXBlockWrapper(self.browser, block_id) self.library_content_page = LibraryContentXBlockWrapper(self.browser, block_id)
self.library_content_page.wait_for_page()
def _auto_auth(self, username, email, staff): def _auto_auth(self, username, email, staff):
""" """
...@@ -132,6 +131,22 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -132,6 +131,22 @@ class LibraryContentTest(UniqueCourseTest):
AutoAuthPage(self.browser, username=username, email=email, AutoAuthPage(self.browser, username=username, email=email,
course_id=self.course_id, staff=staff).visit() course_id=self.course_id, staff=staff).visit()
@ddt.ddt
class LibraryContentTest(LibraryContentTestBase):
"""
Test courseware.
"""
def populate_library_fixture(self, library_fixture):
"""
Populates library fixture with XBlock Fixtures
"""
library_fixture.add_children(
XBlockFixtureDesc("html", "Html1", data='html1'),
XBlockFixtureDesc("html", "Html2", data='html2'),
XBlockFixtureDesc("html", "Html3", data='html3'),
)
@ddt.data(1, 2, 3) @ddt.data(1, 2, 3)
def test_shows_random_xblocks_from_configured(self, count): def test_shows_random_xblocks_from_configured(self, count):
""" """
...@@ -143,7 +158,7 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -143,7 +158,7 @@ class LibraryContentTest(UniqueCourseTest):
When I go to LMS courseware page for library content xblock as student When I go to LMS courseware page for library content xblock as student
Then I can see {count} random xblocks from the library Then I can see {count} random xblocks from the library
""" """
self._refresh_library_content_children(count=count) self._change_library_content_settings(count=count)
self._auto_auth(self.USERNAME, self.EMAIL, False) self._auto_auth(self.USERNAME, self.EMAIL, False)
self._goto_library_block_page() self._goto_library_block_page()
children_contents = self.library_content_page.children_contents children_contents = self.library_content_page.children_contents
...@@ -160,9 +175,128 @@ class LibraryContentTest(UniqueCourseTest): ...@@ -160,9 +175,128 @@ class LibraryContentTest(UniqueCourseTest):
When I go to LMS courseware page for library content xblock as student When I go to LMS courseware page for library content xblock as student
Then I can see all xblocks from the library Then I can see all xblocks from the library
""" """
self._refresh_library_content_children(count=10) self._change_library_content_settings(count=10)
self._auto_auth(self.USERNAME, self.EMAIL, False) self._auto_auth(self.USERNAME, self.EMAIL, False)
self._goto_library_block_page() self._goto_library_block_page()
children_contents = self.library_content_page.children_contents children_contents = self.library_content_page.children_contents
self.assertEqual(len(children_contents), 3) self.assertEqual(len(children_contents), 3)
self.assertEqual(children_contents, self.library_xblocks_texts) self.assertEqual(children_contents, self.library_xblocks_texts)
@ddt.ddt
class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase):
"""
Test Library Content block in LMS
"""
def _get_problem_choice_group_text(self, name, items):
""" Generates Choice Group CAPA problem XML """
items_text = "\n".join([
"<choice correct='{correct}'>{item}</choice>".format(correct=correct, item=item)
for item, correct in items
])
return """<problem>
<p>{name}</p>
<multiplechoiceresponse>
<choicegroup label="{name}" type="MultipleChoice">{items}</choicegroup>
</multiplechoiceresponse>
</problem>""".format(name=name, items=items_text)
def _get_problem_select_text(self, name, items, correct):
""" Generates Select Option CAPA problem XML """
items_text = ",".join(map(lambda item: "'{0}'".format(item), items))
return """<problem>
<p>{name}</p>
<optionresponse>
<optioninput label="{name}" options="({options})" correct="{correct}"></optioninput>
</optionresponse>
</problem>""".format(name=name, options=items_text, correct=correct)
def populate_library_fixture(self, library_fixture):
"""
Populates library fixture with XBlock Fixtures
"""
library_fixture.add_children(
XBlockFixtureDesc(
"problem", "Problem Choice Group 1",
data=self._get_problem_choice_group_text("Problem Choice Group 1 Text", [("1", False), ('2', True)])
),
XBlockFixtureDesc(
"problem", "Problem Choice Group 2",
data=self._get_problem_choice_group_text("Problem Choice Group 2 Text", [("Q", True), ('W', False)])
),
XBlockFixtureDesc(
"problem", "Problem Select 1",
data=self._get_problem_select_text("Problem Select 1 Text", ["Option 1", "Option 2"], "Option 1")
),
XBlockFixtureDesc(
"problem", "Problem Select 2",
data=self._get_problem_select_text("Problem Select 2 Text", ["Option 3", "Option 4"], "Option 4")
),
)
@property
def _problem_headers(self):
""" Expected XBLock headers according to populate_library_fixture """
return frozenset(child.display_name.upper() for child in self.library_fixture.children)
@ddt.data(1, 3)
def test_any_capa_type_shows_all(self, count):
"""
Scenario: Ensure setting "Any Type" for Problem Type does not filter out Problems
Given I have a library with two "Select Option" and two "Choice Group" problems, and a course containing
LibraryContent XBlock configured to draw XBlocks from that library
When I go to studio unit page for library content xblock as staff
And I set library content xblock Problem Type to "Any Type" and Count to {count}
And I refresh library content xblock and pulbish unit
When I go to LMS courseware page for library content xblock as student
Then I can see {count} xblocks from the library of any type
"""
self._change_library_content_settings(count=count, capa_type="Any Type")
self._auto_auth(self.USERNAME, self.EMAIL, False)
self._goto_library_block_page()
children_headers = self.library_content_page.children_headers
self.assertEqual(len(children_headers), count)
self.assertLessEqual(children_headers, self._problem_headers)
@ddt.data(
('Choice Group', 1, ["Problem Choice Group 1", "Problem Choice Group 2"]),
('Select Option', 2, ["Problem Select 1", "Problem Select 2"]),
)
@ddt.unpack
def test_capa_type_shows_only_chosen_type(self, capa_type, count, expected_headers):
"""
Scenario: Ensure setting "{capa_type}" for Problem Type draws aonly problem of {capa_type} from library
Given I have a library with two "Select Option" and two "Choice Group" problems, and a course containing
LibraryContent XBlock configured to draw XBlocks from that library
When I go to studio unit page for library content xblock as staff
And I set library content xblock Problem Type to "{capa_type}" and Count to {count}
And I refresh library content xblock and pulbish unit
When I go to LMS courseware page for library content xblock as student
Then I can see {count} xblocks from the library of {capa_type}
"""
self._change_library_content_settings(count=count, capa_type=capa_type)
self._auto_auth(self.USERNAME, self.EMAIL, False)
self._goto_library_block_page()
children_headers = self.library_content_page.children_headers
self.assertEqual(len(children_headers), count)
self.assertLessEqual(children_headers, self._problem_headers)
self.assertLessEqual(children_headers, set(map(lambda header: header.upper(), expected_headers)))
def test_missing_capa_type_shows_none(self):
"""
Scenario: Ensure setting "{capa_type}" for Problem Type that is not present in library results in empty XBlock
Given I have a library with two "Select Option" and two "Choice Group" problems, and a course containing
LibraryContent XBlock configured to draw XBlocks from that library
When I go to studio unit page for library content xblock as staff
And I set library content xblock Problem Type to type not present in library
And I refresh library content xblock and pulbish unit
When I go to LMS courseware page for library content xblock as student
Then I can see no xblocks
"""
self._change_library_content_settings(count=1, capa_type="Matlab")
self._auto_auth(self.USERNAME, self.EMAIL, False)
self._goto_library_block_page()
children_headers = self.library_content_page.children_headers
self.assertEqual(len(children_headers), 0)
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