def setUp(self): super(DiscussionPreviewTest, self).setUp() cop = CourseOutlinePage( self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"] ) cop.visit() self.unit = cop.section("Test Section").subsection("Test Subsection").expand_subsection().unit("Test Unit") self.unit.go_to()
def setUp(self): super(DiscussionPreviewTest, self).setUp() cop = CourseOutlinePage(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) cop.visit() self.unit = cop.section('Test Section').subsection( 'Test Subsection').expand_subsection().unit('Test Unit') self.unit.go_to()
def test_course_rerun(self): """ Scenario: Courses can be rerun Given I have a course with a section, subsesction, vertical, and html component with content 'Test Content' When I visit the course rerun page And I type 'test_rerun' in the course run field And I click Create Rerun And I visit the course listing page And I wait for all courses to finish processing And I click on the course with run 'test_rerun' Then I see a rerun notification on the course outline page And when I click 'Dismiss' on the notification Then I do not see a rerun notification And when I expand the subsection and click on the unit And I click 'View Live Version' Then I see one html component with the content 'Test Content' """ course_info = (self.course_info['org'], self.course_info['number'], self.course_info['run']) updated_course_info = course_info[0] + "+" + course_info[1] + "+" + course_info[2] self.dashboard_page.visit() self.dashboard_page.scroll_to_course(course_info[1]) self.dashboard_page.create_rerun(updated_course_info) rerun_page = CourseRerunPage(self.browser, *course_info) rerun_page.wait_for_page() course_run = 'test_rerun_' + str(random.randrange(1000000, 9999999)) rerun_page.course_run = course_run rerun_page.create_rerun() def finished_processing(): self.dashboard_page.visit() return not self.dashboard_page.has_processing_courses EmptyPromise(finished_processing, "Rerun finished processing", try_interval=5, timeout=60).fulfill() assert course_run in self.dashboard_page.course_runs self.dashboard_page.click_course_run(course_run) outline_page = CourseOutlinePage(self.browser, *course_info) outline_page.wait_for_page() self.assertTrue(outline_page.has_rerun_notification) outline_page.dismiss_rerun_notification() EmptyPromise(lambda: not outline_page.has_rerun_notification, "Rerun notification dismissed").fulfill() subsection = outline_page.section(self.SECTION_NAME).subsection(self.SUBSECITON_NAME) subsection.expand_subsection() unit_page = subsection.unit(self.UNIT_NAME).go_to() unit_page.view_published_version() courseware = CoursewarePage(self.browser, self.course_id) courseware.wait_for_page() self.assertEqual(courseware.num_xblock_components, 1) self.assertEqual(courseware.xblock_component_html_content(), self.COMPONENT_CONTENT)
def test_course_rerun(self): """ Scenario: Courses can be rerun Given I have a course with a section, subsesction, vertical, and html component with content 'Test Content' When I visit the course rerun page And I type 'test_rerun' in the course run field And I click Create Rerun And I visit the course listing page And I wait for all courses to finish processing And I click on the course with run 'test_rerun' Then I see a rerun notification on the course outline page And when I click 'Dismiss' on the notification Then I do not see a rerun notification And when I expand the subsection and click on the unit And I click 'View Live Version' Then I see one html component with the content 'Test Content' """ course_info = (self.course_info['org'], self.course_info['number'], self.course_info['run']) updated_course_info = course_info[0] + "+" + course_info[1] + "+" + course_info[2] self.dashboard_page.visit() self.dashboard_page.scroll_to_course(course_info[1]) self.dashboard_page.create_rerun(updated_course_info) rerun_page = CourseRerunPage(self.browser, *course_info) rerun_page.wait_for_page() course_run = 'test_rerun_' + str(random.randrange(1000000, 9999999)) rerun_page.course_run = course_run rerun_page.create_rerun() def finished_processing(): self.dashboard_page.visit() return not self.dashboard_page.has_processing_courses EmptyPromise(finished_processing, "Rerun finished processing", try_interval=5, timeout=60).fulfill() assert_in(course_run, self.dashboard_page.course_runs) self.dashboard_page.click_course_run(course_run) outline_page = CourseOutlinePage(self.browser, *course_info) outline_page.wait_for_page() self.assertTrue(outline_page.has_rerun_notification) outline_page.dismiss_rerun_notification() EmptyPromise(lambda: not outline_page.has_rerun_notification, "Rerun notification dismissed").fulfill() subsection = outline_page.section(self.SECTION_NAME).subsection(self.SUBSECITON_NAME) subsection.expand_subsection() unit_page = subsection.unit(self.UNIT_NAME).go_to() unit_page.view_published_version() courseware = CoursewarePage(self.browser, self.course_id) courseware.wait_for_page() self.assertEqual(courseware.num_xblock_components, 1) self.assertEqual(courseware.xblock_component_html_content(), self.COMPONENT_CONTENT)
def setUp(self): super(DiscussionPreviewTest, self).setUp() cop = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) cop.visit() self.unit = cop.section('Test Section').subsection('Test Subsection').expand_subsection().unit('Test Unit') self.unit.go_to()
def record_visit_unit(self, section_title, subsection_title, unit_title): """ Produce a HAR for loading a unit page. """ course_outline_page = CourseOutlinePage(self.browser, self.course_org, self.course_num, self.course_run).visit() course_outline_unit = course_outline_page.section(section_title).subsection(subsection_title).expand_subsection().unit(unit_title) har_name = 'UnitPage_{org}_{course}'.format( org=self.course_org, course=self.course_num ) self.har_capturer.add_page(self.browser, har_name) course_outline_unit.go_to() self.har_capturer.save_har(self.browser, har_name)
class ContainerBase(StudioCourseTest): """ Base class for tests that do operations on the container page. """ def setUp(self, is_staff=False): """ Create a unique identifier for the course used in this test. """ # Ensure that the superclass sets up super(ContainerBase, self).setUp(is_staff=is_staff) self.outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) def go_to_nested_container_page(self): """ Go to the nested container page. """ unit = self.go_to_unit_page() # The 0th entry is the unit page itself. container = unit.xblocks[1].go_to_container() return container def go_to_unit_page(self, section_name='Test Section', subsection_name='Test Subsection', unit_name='Test Unit'): """ Go to the test unit page. If make_draft is true, the unit page will be put into draft mode. """ self.outline.visit() subsection = self.outline.section(section_name).subsection(subsection_name) return subsection.expand_subsection().unit(unit_name).go_to() def do_action_and_verify(self, action, expected_ordering): """ Perform the supplied action and then verify the resulting ordering. """ container = self.go_to_nested_container_page() action(container) verify_ordering(self, container, expected_ordering) # Reload the page to see that the change was persisted. container = self.go_to_nested_container_page() verify_ordering(self, container, expected_ordering)
class LibraryContentTestBase(UniqueCourseTest): """ Base class for library content block tests """ USERNAME = "******" EMAIL = "*****@*****.**" STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" shard = 10 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.studio_course_outline = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) self.library_fixture = LibraryFixture( 'test_org', self.unique_id, u'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': six.text_type(self.library_key), 'mode': 'random', 'max_count': 1, } 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() 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.studio_course_outline.visit() subsection = self.studio_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').results if not paragraphs: course_home_page = CourseHomePage(self.browser, self.course_id) course_home_page.visit() course_home_page.outline.go_to_section_by_index(0, 0) 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()
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, } 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, 2, 3) def test_can_edit_metadata(self, max_count): """ 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 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) 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) 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 """ # Formerly flaky: see TE-745 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)
class XBlockAcidBase(AcceptanceTest): """ 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(XBlockAcidBase, self).setUp() # Define a unique course identifier self.course_info = { 'org': 'test_org', 'number': 'course_' + self.unique_id[:5], 'run': 'test_' + self.unique_id, 'display_name': 'Test Course ' + self.unique_id } self.outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.course_id = '{org}.{number}.{run}'.format(**self.course_info) self.setup_fixtures() self.auth_page = AutoAuthPage( self.browser, staff=False, username=self.user.get('username'), email=self.user.get('email'), password=self.user.get('password') ) self.auth_page.visit() def validate_acid_block_preview(self, acid_block): """ Validate the Acid Block's preview """ self.assertTrue(acid_block.init_fn_passed) self.assertTrue(acid_block.resource_url_passed) self.assertTrue(acid_block.scope_passed('user_state')) self.assertTrue(acid_block.scope_passed('user_state_summary')) self.assertTrue(acid_block.scope_passed('preferences')) self.assertTrue(acid_block.scope_passed('user_info')) def test_acid_block_preview(self): """ Verify that all expected acid block tests pass in studio preview """ self.outline.visit() subsection = self.outline.section('Test Section').subsection('Test Subsection') unit = subsection.expand_subsection().unit('Test Unit').go_to() acid_block = AcidView(self.browser, unit.xblocks[0].preview_selector) self.validate_acid_block_preview(acid_block) def test_acid_block_editor(self): """ Verify that all expected acid block tests pass in studio editor """ self.outline.visit() subsection = self.outline.section('Test Section').subsection('Test Subsection') unit = subsection.expand_subsection().unit('Test Unit').go_to() acid_block = AcidView(self.browser, unit.xblocks[0].edit().editor_selector) self.assertTrue(acid_block.init_fn_passed) self.assertTrue(acid_block.resource_url_passed)
class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest, TestWithSearchIndexMixin): """ Test Library Content block in LMS """ shard = 17 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': six.text_type(self.library_key), 'mode': 'random', 'max_count': 1, } 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, 2, 3) def test_can_edit_metadata(self, max_count): """ 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 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) 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_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)
class CMSVideoBaseTest(UniqueCourseTest): """ CMS Video Module Base Test Class """ def setUp(self): """ Initialization of pages and course fixture for tests """ super(CMSVideoBaseTest, self).setUp() self.video = VideoComponentPage(self.browser) # This will be initialized later self.unit_page = None self.outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.assets = [] self.metadata = None self.addCleanup(YouTubeStubConfig.reset) def _create_course_unit(self, youtube_stub_config=None, subtitles=False): """ Create a Studio Video Course Unit and Navigate to it. Arguments: youtube_stub_config (dict) subtitles (bool) """ if youtube_stub_config: YouTubeStubConfig.configure(youtube_stub_config) if subtitles: self.assets.append('subs_3_yD_cEKoCk.srt.sjson') self.navigate_to_course_unit() def _create_video(self): """ Create Xblock Video Component. """ self.video.create_video() video_xblocks = self.video.xblocks() # Total video xblock components count should be equals to 2 # Why 2? One video component is created by default for each test. Please see # test_studio_video_module.py:CMSVideoTest._create_course_unit # And we are creating second video component here. self.assertEqual(video_xblocks, 2) def _install_course_fixture(self): """ Prepare for tests by creating a course with a section, subsection, and unit. Performs the following: Create a course with a section, subsection, and unit Create a user and make that user a course author Log the user into studio """ if self.assets: self.course_fixture.add_asset(self.assets) # Create course with Video component self.course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('video', 'Video', metadata=self.metadata) ) ) ) ).install() # Auto login and register the course AutoAuthPage( self.browser, staff=False, username=self.course_fixture.user.get('username'), email=self.course_fixture.user.get('email'), password=self.course_fixture.user.get('password') ).visit() def _navigate_to_course_unit_page(self): """ Open the course from the dashboard and expand the section and subsection and click on the Unit link The end result is the page where the user is editing the newly created unit """ # Visit Course Outline page self.outline.visit() # Visit Unit page self.unit_page = self.outline.section('Test Section').subsection('Test Subsection').expand_subsection().unit( 'Test Unit').go_to() self.video.wait_for_video_component_render() def navigate_to_course_unit(self): """ Install the course with required components and navigate to course unit page """ self._install_course_fixture() self._navigate_to_course_unit_page() def edit_component(self, xblock_index=1): """ Open component Edit Dialog for first component on page. Arguments: xblock_index: number starting from 1 (0th entry is the unit page itself) """ self.unit_page.xblocks[xblock_index].edit() EmptyPromise( lambda: self.video.q(css='div.basic_metadata_edit').visible, "Wait for the basic editor to be open", timeout=5 ).fulfill() def open_advanced_tab(self): """ Open components advanced tab. """ # The 0th entry is the unit page itself. self.unit_page.xblocks[1].open_advanced_tab() def open_basic_tab(self): """ Open components basic tab. """ # The 0th entry is the unit page itself. self.unit_page.xblocks[1].open_basic_tab() def save_unit_settings(self): """ Save component settings. """ # The 0th entry is the unit page itself. self.unit_page.xblocks[1].save_settings()
class LibraryContentTestBase(UniqueCourseTest): """ Base class for library content block tests """ USERNAME = "******" EMAIL = "*****@*****.**" STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" 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.studio_course_outline = StudioCourseOutlinePage( 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, } 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.studio_course_outline.visit() subsection = self.studio_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').results if not paragraphs: course_home_page = CourseHomePage(self.browser, self.course_id) course_home_page.visit() course_home_page.outline.go_to_section_by_index(0, 0) 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()
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) 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 """ # Formerly flaky: see TE-745 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)
class XBlockAcidBase(AcceptanceTest): """ 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(XBlockAcidBase, self).setUp() # Define a unique course identifier self.course_info = { "org": "test_org", "number": "course_" + self.unique_id[:5], "run": "test_" + self.unique_id, "display_name": "Test Course " + self.unique_id, } self.outline = CourseOutlinePage( self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"] ) self.course_id = "{org}.{number}.{run}".format(**self.course_info) self.setup_fixtures() self.auth_page = AutoAuthPage( self.browser, staff=False, username=self.user.get("username"), email=self.user.get("email"), password=self.user.get("password"), ) self.auth_page.visit() def validate_acid_block_preview(self, acid_block): """ Validate the Acid Block's preview """ self.assertTrue(acid_block.init_fn_passed) self.assertTrue(acid_block.resource_url_passed) self.assertTrue(acid_block.scope_passed("user_state")) self.assertTrue(acid_block.scope_passed("user_state_summary")) self.assertTrue(acid_block.scope_passed("preferences")) self.assertTrue(acid_block.scope_passed("user_info")) def test_acid_block_preview(self): """ Verify that all expected acid block tests pass in studio preview """ self.outline.visit() subsection = self.outline.section("Test Section").subsection("Test Subsection") unit = subsection.expand_subsection().unit("Test Unit").go_to() acid_block = AcidView(self.browser, unit.xblocks[0].preview_selector) self.validate_acid_block_preview(acid_block) def test_acid_block_editor(self): """ Verify that all expected acid block tests pass in studio editor """ self.outline.visit() subsection = self.outline.section("Test Section").subsection("Test Subsection") unit = subsection.expand_subsection().unit("Test Unit").go_to() acid_block = AcidView(self.browser, unit.xblocks[0].edit().editor_selector) self.assertTrue(acid_block.init_fn_passed) self.assertTrue(acid_block.resource_url_passed)
class XBlockAcidBase(AcceptanceTest): """ Base class for tests that verify that XBlock integration is working correctly """ shard = 21 __test__ = False def setUp(self): """ Create a unique identifier for the course used in this test. """ # Ensure that the superclass sets up super(XBlockAcidBase, self).setUp() # Define a unique course identifier self.course_info = { 'org': 'test_org', 'number': 'course_' + self.unique_id[:5], 'run': 'test_' + self.unique_id, 'display_name': 'Test Course ' + self.unique_id } self.outline = CourseOutlinePage(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) self.course_id = '{org}.{number}.{run}'.format(**self.course_info) self.setup_fixtures() self.auth_page = AutoAuthPage(self.browser, staff=False, username=self.user.get('username'), email=self.user.get('email'), password=self.user.get('password')) self.auth_page.visit() def validate_acid_block_preview(self, acid_block): """ Validate the Acid Block's preview """ self.assertTrue(acid_block.init_fn_passed) self.assertTrue(acid_block.resource_url_passed) self.assertTrue(acid_block.scope_passed('user_state')) self.assertTrue(acid_block.scope_passed('user_state_summary')) self.assertTrue(acid_block.scope_passed('preferences')) self.assertTrue(acid_block.scope_passed('user_info')) def test_acid_block_preview(self): """ Verify that all expected acid block tests pass in studio preview """ self.outline.visit() subsection = self.outline.section('Test Section').subsection( 'Test Subsection') unit = subsection.expand_subsection().unit('Test Unit').go_to() acid_block = AcidView(self.browser, unit.xblocks[0].preview_selector) self.validate_acid_block_preview(acid_block) def test_acid_block_editor(self): """ Verify that all expected acid block tests pass in studio editor """ self.outline.visit() subsection = self.outline.section('Test Section').subsection( 'Test Subsection') unit = subsection.expand_subsection().unit('Test Unit').go_to() acid_block = AcidView(self.browser, unit.xblocks[0].edit().editor_selector) self.assertTrue(acid_block.init_fn_passed) self.assertTrue(acid_block.resource_url_passed)
class CMSVideoBaseTest(UniqueCourseTest): """ CMS Video Module Base Test Class """ def setUp(self): """ Initialization of pages and course fixture for tests """ super(CMSVideoBaseTest, self).setUp() self.video = VideoComponentPage(self.browser) # This will be initialized later self.unit_page = None self.outline = CourseOutlinePage(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) self.course_fixture = CourseFixture(self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) self.assets = [] self.metadata = None self.addCleanup(YouTubeStubConfig.reset) def _create_course_unit(self, youtube_stub_config=None, subtitles=False): """ Create a Studio Video Course Unit and Navigate to it. Arguments: youtube_stub_config (dict) subtitles (bool) """ if youtube_stub_config: YouTubeStubConfig.configure(youtube_stub_config) if subtitles: self.assets.append('subs_3_yD_cEKoCk.srt.sjson') self.navigate_to_course_unit() def _create_video(self): """ Create Xblock Video Component. """ self.video.create_video() video_xblocks = self.video.xblocks() # Total video xblock components count should be equals to 2 # Why 2? One video component is created by default for each test. Please see # test_studio_video_module.py:CMSVideoTest._create_course_unit # And we are creating second video component here. self.assertEqual(video_xblocks, 2) def _install_course_fixture(self): """ Prepare for tests by creating a course with a section, subsection, and unit. Performs the following: Create a course with a section, subsection, and unit Create a user and make that user a course author Log the user into studio """ if self.assets: self.course_fixture.add_asset(self.assets) # Create course with Video component self.course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'video', 'Video', metadata=self.metadata))))).install() # Auto login and register the course AutoAuthPage( self.browser, staff=False, username=self.course_fixture.user.get('username'), email=self.course_fixture.user.get('email'), password=self.course_fixture.user.get('password')).visit() def _navigate_to_course_unit_page(self): """ Open the course from the dashboard and expand the section and subsection and click on the Unit link The end result is the page where the user is editing the newly created unit """ # Visit Course Outline page self.outline.visit() # Visit Unit page self.unit_page = self.outline.section('Test Section').subsection( 'Test Subsection').expand_subsection().unit('Test Unit').go_to() self.video.wait_for_video_component_render() def navigate_to_course_unit(self): """ Install the course with required components and navigate to course unit page """ self._install_course_fixture() self._navigate_to_course_unit_page() def edit_component(self, xblock_index=1): """ Open component Edit Dialog for first component on page. Arguments: xblock_index: number starting from 1 (0th entry is the unit page itself) """ self.unit_page.xblocks[xblock_index].edit() EmptyPromise( lambda: self.video.q(css='div.basic_metadata_edit').visible, "Wait for the basic editor to be open", timeout=5).fulfill() def open_advanced_tab(self): """ Open components advanced tab. """ # The 0th entry is the unit page itself. self.unit_page.xblocks[1].open_advanced_tab() def open_basic_tab(self): """ Open components basic tab. """ # The 0th entry is the unit page itself. self.unit_page.xblocks[1].open_basic_tab() def save_unit_settings(self): """ Save component settings. """ # The 0th entry is the unit page itself. self.unit_page.xblocks[1].save_settings()