From 2b45e10f340ba51fc3a4dca9221fc7fe65fead53 Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Mon, 22 Dec 2014 18:37:05 +0300 Subject: [PATCH] Bok choy acceptance tests --- .../xmodule/xmodule/library_content_module.py | 16 +- common/test/acceptance/pages/lms/library.py | 11 ++ .../test/acceptance/pages/studio/library.py | 19 ++ .../test/acceptance/tests/lms/test_library.py | 162 ++++++++++++++++-- 4 files changed, 188 insertions(+), 20 deletions(-) diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py index 8a59c4a764..e2e2481324 100644 --- a/common/lib/xmodule/xmodule/library_content_module.py +++ b/common/lib/xmodule/xmodule/library_content_module.py @@ -35,8 +35,10 @@ def enum(**enums): def _get_capa_types(): + """ + Gets capa types tags and labels + """ capa_types = { - ANY_CAPA_TYPE_VALUE: _('Any Type'), 'annotationinput': _('Annotation'), 'checkboxgroup': _('Checkbox Group'), 'checkboxtextgroup': _('Checkbox Text Group'), @@ -54,7 +56,7 @@ def _get_capa_types(): 'javascriptinput': _('Javascript Input'), 'jsinput': _('JS Input'), 'matlabinput': _('Matlab'), - 'optioninput': _('Select option'), + 'optioninput': _('Select Option'), 'radiogroup': _('Radio Group'), 'radiotextgroup': _('Radio Text Group'), 'schematic': _('Schematic'), @@ -63,7 +65,7 @@ def _get_capa_types(): 'vsepr_input': _('VSEPR'), } - return sorted([ + return [{'value': ANY_CAPA_TYPE_VALUE, 'display_name': _('Any Type')}] + sorted([ {'value': capa_type, 'display_name': caption} for capa_type, caption in capa_types.items() ], key=lambda item: item.get('display_name')) @@ -221,6 +223,9 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule): any particular student. """ def _filter_children(self, child_locator): + """ + Filters children by CAPA problem type, if configured + """ if self.capa_type == ANY_CAPA_TYPE_VALUE: return True @@ -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()) - def selected_children(self): """ Returns a set() of block_ids indicating which of the possible children @@ -427,8 +431,8 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe If source_libraries has been edited, refresh_children automatically. """ old_source_libraries = LibraryList().from_json(old_metadata.get('source_libraries', [])) - if (set(old_source_libraries) != set(self.source_libraries) or - old_metadata.get('capa_type', ANY_CAPA_TYPE_VALUE) != self.capa_type): + if set(old_source_libraries) != set(self.source_libraries) or \ + old_metadata.get('capa_type', ANY_CAPA_TYPE_VALUE) != self.capa_type: try: self.refresh_children(None, None, update_db=False) # update_db=False since update_item() is about to be called anyways except ValueError: diff --git a/common/test/acceptance/pages/lms/library.py b/common/test/acceptance/pages/lms/library.py index 8655fae79f..3397082344 100644 --- a/common/test/acceptance/pages/lms/library.py +++ b/common/test/acceptance/pages/lms/library.py @@ -16,6 +16,9 @@ class LibraryContentXBlockWrapper(PageObject): self.locator = locator def is_browser_on_page(self): + """ + Checks if page is opened + """ return self.q(css='{}[data-id="{}"]'.format(self.BODY_SELECTOR, self.locator)).present def _bounded_selector(self, selector): @@ -35,3 +38,11 @@ class LibraryContentXBlockWrapper(PageObject): """ child_blocks = self.q(css=self._bounded_selector("div[data-id]")) 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) diff --git a/common/test/acceptance/pages/studio/library.py b/common/test/acceptance/pages/studio/library.py index ea7f2299f9..71df4c4ad1 100644 --- a/common/test/acceptance/pages/studio/library.py +++ b/common/test/acceptance/pages/studio/library.py @@ -122,6 +122,7 @@ class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject): LIBRARY_LABEL = "Libraries" COUNT_LABEL = "Count" SCORED_LABEL = "Scored" + PROBLEM_TYPE_LABEL = "Problem Type" def is_browser_on_page(self): """ @@ -196,6 +197,24 @@ class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject): scored_select.select_by_value(str(scored)) 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): """ Adds library key input diff --git a/common/test/acceptance/tests/lms/test_library.py b/common/test/acceptance/tests/lms/test_library.py index f83e6b94e9..4d6f34e822 100644 --- a/common/test/acceptance/tests/lms/test_library.py +++ b/common/test/acceptance/tests/lms/test_library.py @@ -19,22 +19,22 @@ SUBSECTION_NAME = 'Test Subsection' UNIT_NAME = 'Test Unit' -@ddt.ddt -class LibraryContentTest(UniqueCourseTest): - """ - Test courseware. - """ +class LibraryContentTestBase(UniqueCourseTest): + """ Base class for library content block tests """ USERNAME = "STUDENT_TESTER" EMAIL = "student101@example.com" STAFF_USERNAME = "STAFF_TESTER" STAFF_EMAIL = "staff101@example.com" + def populate_library_fixture(self, library_fixture): + pass + def setUp(self): """ 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) @@ -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.add_children( - XBlockFixtureDesc("html", "Html1", data='html1'), - XBlockFixtureDesc("html", "Html2", data='html2'), - XBlockFixtureDesc("html", "Html3", data='html3'), - ) + self.populate_library_fixture(self.library_fixture) self.library_fixture.install() self.library_info = self.library_fixture.library_info @@ -83,7 +79,7 @@ class LibraryContentTest(UniqueCourseTest): 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 """ @@ -91,6 +87,8 @@ class LibraryContentTest(UniqueCourseTest): library_container_block = StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(unit_page.xblocks[0]) modal = StudioLibraryContentXBlockEditModal(library_container_block.edit()) modal.count = count + if capa_type is not None: + modal.capa_type = capa_type library_container_block.save_settings() self._go_to_unit_page(change_login=False) unit_page.wait_for_page() @@ -124,6 +122,7 @@ class LibraryContentTest(UniqueCourseTest): block_id = block_id if block_id is not None else self.lib_block.locator #pylint: disable=attribute-defined-outside-init self.library_content_page = LibraryContentXBlockWrapper(self.browser, block_id) + self.library_content_page.wait_for_page() def _auto_auth(self, username, email, staff): """ @@ -132,6 +131,22 @@ class LibraryContentTest(UniqueCourseTest): AutoAuthPage(self.browser, username=username, email=email, 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) def test_shows_random_xblocks_from_configured(self, count): """ @@ -143,7 +158,7 @@ class LibraryContentTest(UniqueCourseTest): When I go to LMS courseware page for library content xblock as student 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._goto_library_block_page() children_contents = self.library_content_page.children_contents @@ -160,9 +175,128 @@ class LibraryContentTest(UniqueCourseTest): When I go to LMS courseware page for library content xblock as student 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._goto_library_block_page() children_contents = self.library_content_page.children_contents self.assertEqual(len(children_contents), 3) 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([ + "{item}".format(correct=correct, item=item) + for item, correct in items + ]) + + return """ +

{name}

+ + {items} + +
""".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 """ +

{name}

+ + + +
""".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)