""" Acceptance tests for Library Content in LMS """ import ddt from flaky import flaky from nose.plugins.attrib import attr import textwrap from .base_studio_test import StudioLibraryTest from ...fixtures.course import CourseFixture from ..helpers import UniqueCourseTest, TestWithSearchIndexMixin from ...pages.studio.library import StudioLibraryContentEditor, StudioLibraryContainerXBlockWrapper from ...pages.studio.overview import CourseOutlinePage from ...fixtures.course import XBlockFixtureDesc SECTION_NAME = 'Test Section' SUBSECTION_NAME = 'Test Subsection' UNIT_NAME = 'Test Unit' @attr('shard_5') @ddt.ddt class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest, TestWithSearchIndexMixin): """ Test Library Content block in LMS """ def setUp(self): """ Install library with some content and a course using fixtures """ self._create_search_index() super(StudioLibraryContainerTest, self).setUp() # Also create a course: self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.populate_course_fixture(self.course_fixture) self.course_fixture.install() self.outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.outline.visit() subsection = self.outline.section(SECTION_NAME).subsection(SUBSECTION_NAME) self.unit_page = subsection.expand_subsection().unit(UNIT_NAME).go_to() def tearDown(self): """ Tear down method: remove search index backing file """ self._cleanup_index_file() super(StudioLibraryContainerTest, self).tearDown() def populate_library_fixture(self, library_fixture): """ Populate the children of the test course fixture. """ library_fixture.add_children( XBlockFixtureDesc("html", "Html1"), XBlockFixtureDesc("html", "Html2"), XBlockFixtureDesc("html", "Html3"), ) def populate_course_fixture(self, course_fixture): """ Install a course with sections/problems, tabs, updates, and handouts """ library_content_metadata = { 'source_library_id': unicode(self.library_key), 'mode': 'random', 'max_count': 1, 'has_score': False } course_fixture.add_children( XBlockFixtureDesc('chapter', SECTION_NAME).add_children( XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children( XBlockFixtureDesc('vertical', UNIT_NAME).add_children( XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata) ) ) ) ) def _get_library_xblock_wrapper(self, xblock): """ Wraps xblock into :class:`...pages.studio.library.StudioLibraryContainerXBlockWrapper` """ return StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(xblock) @ddt.data( (1, True), (2, False), (3, True), ) @ddt.unpack def test_can_edit_metadata(self, max_count, scored): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And I edit library content metadata and save it Then I can ensure that data is persisted """ library_name = self.library_info['display_name'] library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) edit_modal.library_name = library_name edit_modal.count = max_count edit_modal.scored = scored library_container.save_settings() # saving settings # open edit window again to verify changes are persistent library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) self.assertEqual(edit_modal.library_name, library_name) self.assertEqual(edit_modal.count, max_count) self.assertEqual(edit_modal.scored, scored) def test_no_library_shows_library_not_configured(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And I edit to select "No Library" Then I can see that library content block is misconfigured """ expected_text = 'A library has not yet been selected.' expected_action = 'Select a Library' library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) # precondition check - the library block should be configured before we remove the library setting self.assertFalse(library_container.has_validation_not_configured_warning) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) edit_modal.library_name = "No Library Selected" library_container.save_settings() self.assertTrue(library_container.has_validation_not_configured_warning) self.assertIn(expected_text, library_container.validation_not_configured_warning_text) self.assertIn(expected_action, library_container.validation_not_configured_warning_text) @flaky # TODO fix this, see TE-745 def test_out_of_date_message(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block Then I update the library being used Then I refresh the page Then I can see that library content block needs to be updated When I click on the update link Then I can see that the content no longer needs to be updated """ expected_text = "This component is out of date. The library has new content." library_block = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) self.assertFalse(library_block.has_validation_warning) # Removed this assert until a summary message is added back to the author view (SOL-192) #self.assertIn("3 matching components", library_block.author_content) self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc("html", "Html4")) self.unit_page.visit() # Reload the page self.assertTrue(library_block.has_validation_warning) self.assertIn(expected_text, library_block.validation_warning_text) library_block.refresh_children() self.unit_page.wait_for_page() # Wait for the page to reload library_block = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) self.assertFalse(library_block.has_validation_message) # Removed this assert until a summary message is added back to the author view (SOL-192) #self.assertIn("4 matching components", library_block.author_content) def test_no_content_message(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And I set Problem Type selector so that no libraries have matching content Then I can see that "No matching content" warning is shown When I set Problem Type selector so that there is matching content Then I can see that warning messages are not shown """ # Add a single "Dropdown" type problem to the library (which otherwise has only HTML blocks): self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc( "problem", "Dropdown", data=textwrap.dedent(""" <problem> <p>Dropdown</p> <optionresponse><optioninput label="Dropdown" options="('1', '2')" correct="'2'"></optioninput></optionresponse> </problem> """) )) expected_text = 'There are no matching problem types in the specified libraries. Select another problem type' library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) # precondition check - assert library has children matching filter criteria self.assertFalse(library_container.has_validation_error) self.assertFalse(library_container.has_validation_warning) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) self.assertEqual(edit_modal.capa_type, "Any Type") # precondition check edit_modal.capa_type = "Custom Evaluated Script" library_container.save_settings() self.assertTrue(library_container.has_validation_warning) self.assertIn(expected_text, library_container.validation_warning_text) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) self.assertEqual(edit_modal.capa_type, "Custom Evaluated Script") # precondition check edit_modal.capa_type = "Dropdown" library_container.save_settings() # Library should contain single Dropdown problem, so now there should be no errors again self.assertFalse(library_container.has_validation_error) self.assertFalse(library_container.has_validation_warning) def test_not_enough_children_blocks(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And I set Problem Type selector so "Any" Then I can see that "No matching content" warning is shown """ expected_tpl = "The specified library is configured to fetch {count} problems, " \ "but there are only {actual} matching problems." library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) # precondition check - assert block is configured fine self.assertFalse(library_container.has_validation_error) self.assertFalse(library_container.has_validation_warning) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) edit_modal.count = 50 library_container.save_settings() self.assertTrue(library_container.has_validation_warning) self.assertIn( expected_tpl.format(count=50, actual=len(self.library_fixture.children)), library_container.validation_warning_text ) def test_settings_overrides(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And when I click the "View" link Then I can see a preview of the blocks drawn from the library. When I edit one of the blocks to change a setting such as "display_name", Then I can see the new setting is overriding the library version. When I subsequently click to refresh the content with the latest from the library, Then I can see that the overrided version of the setting is preserved. When I click to edit the block and reset the setting, then I can see that the setting's field defaults back to the library version. """ block_wrapper_unit_page = self._get_library_xblock_wrapper(self.unit_page.xblocks[0].children[0]) container_page = block_wrapper_unit_page.go_to_container() library_block = self._get_library_xblock_wrapper(container_page.xblocks[0]) self.assertFalse(library_block.has_validation_message) self.assertEqual(len(library_block.children), 3) block = library_block.children[0] self.assertIn(block.name, ("Html1", "Html2", "Html3")) name_default = block.name block.edit() new_display_name = "A new name for this HTML block" block.set_field_val("Display Name", new_display_name) block.save_settings() self.assertEqual(block.name, new_display_name) # Create a new block, causing a new library version: self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc("html", "Html4")) container_page.visit() # Reload self.assertTrue(library_block.has_validation_warning) library_block.refresh_children() container_page.wait_for_page() # Wait for the page to reload self.assertEqual(len(library_block.children), 4) self.assertEqual(block.name, new_display_name) # Reset: block.edit() block.reset_field_val("Display Name") block.save_settings() self.assertEqual(block.name, name_default) def test_cannot_manage(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And when I click the "View" link Then I can see a preview of the blocks drawn from the library. And I do not see a duplicate button And I do not see a delete button """ block_wrapper_unit_page = self._get_library_xblock_wrapper(self.unit_page.xblocks[0].children[0]) container_page = block_wrapper_unit_page.go_to_container() for block in container_page.xblocks: self.assertFalse(block.has_duplicate_button) self.assertFalse(block.has_delete_button) self.assertFalse(block.has_edit_visibility_button)