# -*- coding: utf-8 -*- """ End-to-end tests for LibraryContent block in LMS """ import ddt import textwrap from nose.plugins.attrib import attr from ..helpers import UniqueCourseTest, TestWithSearchIndexMixin from ...pages.studio.auto_auth import AutoAuthPage from ...pages.studio.overview import CourseOutlinePage from ...pages.studio.library import StudioLibraryContentEditor, StudioLibraryContainerXBlockWrapper from ...pages.lms.courseware import CoursewarePage from ...pages.lms.library import LibraryContentXBlockWrapper from ...pages.common.logout import LogoutPage from ...fixtures.course import CourseFixture, XBlockFixtureDesc from ...fixtures.library import LibraryFixture SECTION_NAME = 'Test Section' SUBSECTION_NAME = 'Test Subsection' UNIT_NAME = 'Test Unit' @attr('shard_3') 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): """ To be overwritten by subclassed tests. Used to install a library to run tests on. """ def setUp(self): """ Set up library, course and library content XBlock """ super(LibraryContentTestBase, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.library_fixture = LibraryFixture('test_org', self.unique_id, 'Test Library {}'.format(self.unique_id)) self.populate_library_fixture(self.library_fixture) self.library_fixture.install() self.library_info = self.library_fixture.library_info self.library_key = self.library_fixture.library_key # Install a course with library content xblock self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) library_content_metadata = { 'source_library_id': unicode(self.library_key), 'mode': 'random', 'max_count': 1, 'has_score': False } self.lib_block = XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata) self.course_fixture.add_children( XBlockFixtureDesc('chapter', SECTION_NAME).add_children( XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children( XBlockFixtureDesc('vertical', UNIT_NAME).add_children( self.lib_block ) ) ) ) self.course_fixture.install() def _change_library_content_settings(self, count=1, capa_type=None): """ Performs library block refresh in Studio, configuring it to show {count} children """ unit_page = self._go_to_unit_page(True) library_container_block = StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(unit_page.xblocks[1]) library_container_block.edit() editor = StudioLibraryContentEditor(self.browser, library_container_block.locator) editor.count = count if capa_type is not None: editor.capa_type = capa_type editor.save() self._go_to_unit_page(change_login=False) unit_page.wait_for_page() unit_page.publish_action.click() unit_page.wait_for_ajax() self.assertIn("Published and Live", unit_page.publish_title) @property def library_xblocks_texts(self): """ Gets texts of all xblocks in library """ return frozenset(child.data for child in self.library_fixture.children) def _go_to_unit_page(self, change_login=True): """ Open unit page in Studio """ if change_login: LogoutPage(self.browser).visit() self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.course_outline.visit() subsection = self.course_outline.section(SECTION_NAME).subsection(SUBSECTION_NAME) return subsection.expand_subsection().unit(UNIT_NAME).go_to() def _goto_library_block_page(self, block_id=None): """ Open library page in LMS """ self.courseware_page.visit() paragraphs = self.courseware_page.q(css='.course-content p') if paragraphs and "You were most recently in" in paragraphs.text[0]: paragraphs[0].find_element_by_tag_name('a').click() 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): """ Logout and login with given credentials. """ AutoAuthPage(self.browser, username=username, email=email, course_id=self.course_id, staff=staff).visit() @ddt.ddt @attr('shard_3') 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): """ Scenario: Ensures that library content shows {count} random xblocks from library in LMS Given I have a library, a course and a LibraryContent block in that course When I go to studio unit page for library content xblock as staff And I set library content xblock to display {count} random children 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} random xblocks from the library """ 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 self.assertEqual(len(children_contents), count) self.assertLessEqual(children_contents, self.library_xblocks_texts) def test_shows_all_if_max_set_to_greater_value(self): """ Scenario: Ensures that library content shows {count} random xblocks from library in LMS Given I have a library, a course and a LibraryContent block in that course When I go to studio unit page for library content xblock as staff And I set library content xblock to display more children than library have 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 all xblocks from the library """ 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 @attr('shard_3') class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase, TestWithSearchIndexMixin): """ Test Library Content block in LMS """ def setUp(self): """ SetUp method """ self._create_search_index() super(StudioLibraryContainerCapaFilterTest, self).setUp() def tearDown(self): self._cleanup_index_file() super(StudioLibraryContainerCapaFilterTest, self).tearDown() 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 textwrap.dedent(""" <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(["'{0}'".format(item) for item in items]) return textwrap.dedent(""" <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 """ items = ( 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") ), ) library_fixture.add_children(*items) @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) def _set_library_content_settings(self, count=1, capa_type="Any Type"): """ Sets library content XBlock parameters, saves, publishes unit, goes to LMS unit page and gets children XBlock headers to assert against them """ self._change_library_content_settings(count=count, capa_type=capa_type) self._auto_auth(self.USERNAME, self.EMAIL, False) self._goto_library_block_page() return self.library_content_page.children_headers def test_problem_type_selector(self): """ 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 set library content xblock Problem Type to "Any Type" and Count to 3 and publish unit When I go to LMS courseware page for library content xblock as student Then I can see 3 xblocks from the library of any type When I set library content xblock Problem Type to "Choice Group" and Count to 1 and publish unit When I go to LMS courseware page for library content xblock as student Then I can see 1 xblock from the library of "Choice Group" type When I set library content xblock Problem Type to "Select Option" and Count to 2 and publish unit When I go to LMS courseware page for library content xblock as student Then I can see 2 xblock from the library of "Select Option" type When I set library content xblock Problem Type to "Matlab" and Count to 2 and publish unit When I go to LMS courseware page for library content xblock as student Then I can see 0 xblocks from the library """ children_headers = self._set_library_content_settings(count=3, capa_type="Any Type") self.assertEqual(len(children_headers), 3) self.assertLessEqual(children_headers, self._problem_headers) # Choice group test children_headers = self._set_library_content_settings(count=1, capa_type="Multiple Choice") self.assertEqual(len(children_headers), 1) self.assertLessEqual( children_headers, set([header.upper() for header in ["Problem Choice Group 1", "Problem Choice Group 2"]]) ) # Choice group test children_headers = self._set_library_content_settings(count=2, capa_type="Dropdown") self.assertEqual(len(children_headers), 2) self.assertEqual( children_headers, set([header.upper() for header in ["Problem Select 1", "Problem Select 2"]]) ) # Missing problem type test children_headers = self._set_library_content_settings(count=2, capa_type="Custom Evaluated Script") self.assertEqual(children_headers, set())