LibraryContent bok choy acceptance tests
This commit is contained in:
@@ -119,6 +119,7 @@ class LibraryContentFields(object):
|
||||
scope=Scope.settings,
|
||||
)
|
||||
mode = String(
|
||||
display_name=_("Mode"),
|
||||
help=_("Determines how content is drawn from the library"),
|
||||
default="random",
|
||||
values=[
|
||||
|
||||
@@ -375,5 +375,3 @@ class CourseFixture(XBlockContainerFixture):
|
||||
"""
|
||||
super(CourseFixture, self)._create_xblock_children(parent_loc, xblock_descriptions)
|
||||
self._publish_xblock(parent_loc)
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ class LibraryFixture(XBlockContainerFixture):
|
||||
'display_name': display_name
|
||||
}
|
||||
|
||||
self.display_name = display_name
|
||||
self._library_key = None
|
||||
super(LibraryFixture, self).__init__()
|
||||
|
||||
|
||||
37
common/test/acceptance/pages/lms/library.py
Normal file
37
common/test/acceptance/pages/lms/library.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Library Content XBlock Wrapper
|
||||
"""
|
||||
from bok_choy.page_object import PageObject
|
||||
|
||||
|
||||
class LibraryContentXBlockWrapper(PageObject):
|
||||
"""
|
||||
A PageObject representing a wrapper around a LibraryContent block seen in the LMS
|
||||
"""
|
||||
url = None
|
||||
BODY_SELECTOR = '.xblock-student_view div'
|
||||
|
||||
def __init__(self, browser, locator):
|
||||
super(LibraryContentXBlockWrapper, self).__init__(browser)
|
||||
self.locator = locator
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='{}[data-id="{}"]'.format(self.BODY_SELECTOR, self.locator)).present
|
||||
|
||||
def _bounded_selector(self, selector):
|
||||
"""
|
||||
Return `selector`, but limited to this particular block's context
|
||||
"""
|
||||
return '{}[data-id="{}"] {}'.format(
|
||||
self.BODY_SELECTOR,
|
||||
self.locator,
|
||||
selector
|
||||
)
|
||||
|
||||
@property
|
||||
def children_contents(self):
|
||||
"""
|
||||
Gets contents of all child XBlocks as list of strings
|
||||
"""
|
||||
child_blocks = self.q(css=self._bounded_selector("div[data-id]"))
|
||||
return frozenset(child.text for child in child_blocks)
|
||||
@@ -3,8 +3,12 @@ Library edit page in Studio
|
||||
"""
|
||||
|
||||
from bok_choy.page_object import PageObject
|
||||
from ...pages.studio.pagination import PaginatedMixin
|
||||
from bok_choy.promise import EmptyPromise
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support.select import Select
|
||||
from .overview import CourseOutlineModal
|
||||
from .container import XBlockWrapper
|
||||
from ...pages.studio.pagination import PaginatedMixin
|
||||
from ...tests.helpers import disable_animations
|
||||
from .utils import confirm_prompt, wait_for_notification
|
||||
from . import BASE_URL
|
||||
@@ -48,7 +52,10 @@ class LibraryPage(PageObject, PaginatedMixin):
|
||||
for improved test reliability.
|
||||
"""
|
||||
self.wait_for_ajax()
|
||||
self.wait_for_element_invisibility('.ui-loading', 'Wait for the page to complete its initial loading of XBlocks via AJAX')
|
||||
self.wait_for_element_invisibility(
|
||||
'.ui-loading',
|
||||
'Wait for the page to complete its initial loading of XBlocks via AJAX'
|
||||
)
|
||||
disable_animations(self)
|
||||
|
||||
@property
|
||||
@@ -80,14 +87,18 @@ class LibraryPage(PageObject, PaginatedMixin):
|
||||
Create an XBlockWrapper for each XBlock div found on the page.
|
||||
"""
|
||||
prefix = '.wrapper-xblock.level-page '
|
||||
return self.q(css=prefix + XBlockWrapper.BODY_SELECTOR).map(lambda el: XBlockWrapper(self.browser, el.get_attribute('data-locator'))).results
|
||||
return self.q(css=prefix + XBlockWrapper.BODY_SELECTOR).map(
|
||||
lambda el: XBlockWrapper(self.browser, el.get_attribute('data-locator'))
|
||||
).results
|
||||
|
||||
def _div_for_xblock_id(self, xblock_id):
|
||||
"""
|
||||
Given an XBlock's usage locator as a string, return the WebElement for
|
||||
that block's wrapper div.
|
||||
"""
|
||||
return self.q(css='.wrapper-xblock.level-page .studio-xblock-wrapper').filter(lambda el: el.get_attribute('data-locator') == xblock_id)
|
||||
return self.q(css='.wrapper-xblock.level-page .studio-xblock-wrapper').filter(
|
||||
lambda el: el.get_attribute('data-locator') == xblock_id
|
||||
)
|
||||
|
||||
def _action_btn_for_xblock_id(self, xblock_id, action):
|
||||
"""
|
||||
@@ -95,4 +106,162 @@ class LibraryPage(PageObject, PaginatedMixin):
|
||||
buttons.
|
||||
action is 'edit', 'duplicate', or 'delete'
|
||||
"""
|
||||
return self._div_for_xblock_id(xblock_id)[0].find_element_by_css_selector('.header-actions .{action}-button.action-button'.format(action=action))
|
||||
return self._div_for_xblock_id(xblock_id)[0].find_element_by_css_selector(
|
||||
'.header-actions .{action}-button.action-button'.format(action=action)
|
||||
)
|
||||
|
||||
|
||||
class StudioLibraryContentXBlockEditModal(CourseOutlineModal, PageObject):
|
||||
"""
|
||||
Library Content XBlock Modal edit window
|
||||
"""
|
||||
url = None
|
||||
MODAL_SELECTOR = ".wrapper-modal-window-edit-xblock"
|
||||
|
||||
# Labels used to identify the fields on the edit modal:
|
||||
LIBRARY_LABEL = "Libraries"
|
||||
COUNT_LABEL = "Count"
|
||||
SCORED_LABEL = "Scored"
|
||||
|
||||
def is_browser_on_page(self):
|
||||
"""
|
||||
Check that we are on the right page in the browser.
|
||||
"""
|
||||
return self.is_shown()
|
||||
|
||||
@property
|
||||
def library_key(self):
|
||||
"""
|
||||
Gets value of first library key input
|
||||
"""
|
||||
library_key_input = self.get_metadata_input(self.LIBRARY_LABEL)
|
||||
if library_key_input is not None:
|
||||
return library_key_input.get_attribute('value').strip(',')
|
||||
return None
|
||||
|
||||
@library_key.setter
|
||||
def library_key(self, library_key):
|
||||
"""
|
||||
Sets value of first library key input, creating it if necessary
|
||||
"""
|
||||
library_key_input = self.get_metadata_input(self.LIBRARY_LABEL)
|
||||
if library_key_input is None:
|
||||
library_key_input = self._add_library_key()
|
||||
if library_key is not None:
|
||||
# can't use lib_text.clear() here as input get deleted by client side script
|
||||
library_key_input.send_keys(Keys.HOME)
|
||||
library_key_input.send_keys(Keys.SHIFT, Keys.END)
|
||||
library_key_input.send_keys(library_key)
|
||||
else:
|
||||
library_key_input.clear()
|
||||
EmptyPromise(lambda: self.library_key == library_key, "library_key is updated in modal.").fulfill()
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
"""
|
||||
Gets value of children count input
|
||||
"""
|
||||
return int(self.get_metadata_input(self.COUNT_LABEL).get_attribute('value'))
|
||||
|
||||
@count.setter
|
||||
def count(self, count):
|
||||
"""
|
||||
Sets value of children count input
|
||||
"""
|
||||
count_text = self.get_metadata_input(self.COUNT_LABEL)
|
||||
count_text.clear()
|
||||
count_text.send_keys(count)
|
||||
EmptyPromise(lambda: self.count == count, "count is updated in modal.").fulfill()
|
||||
|
||||
@property
|
||||
def scored(self):
|
||||
"""
|
||||
Gets value of scored select
|
||||
"""
|
||||
value = self.get_metadata_input(self.SCORED_LABEL).get_attribute('value')
|
||||
if value == 'True':
|
||||
return True
|
||||
elif value == 'False':
|
||||
return False
|
||||
raise ValueError("Unknown value {value} set for {label}".format(value=value, label=self.SCORED_LABEL))
|
||||
|
||||
@scored.setter
|
||||
def scored(self, scored):
|
||||
"""
|
||||
Sets value of scored select
|
||||
"""
|
||||
select_element = self.get_metadata_input(self.SCORED_LABEL)
|
||||
select_element.click()
|
||||
scored_select = Select(select_element)
|
||||
scored_select.select_by_value(str(scored))
|
||||
EmptyPromise(lambda: self.scored == scored, "scored is updated in modal.").fulfill()
|
||||
|
||||
def _add_library_key(self):
|
||||
"""
|
||||
Adds library key input
|
||||
"""
|
||||
wrapper = self._get_metadata_element(self.LIBRARY_LABEL)
|
||||
add_button = wrapper.find_element_by_xpath(".//a[contains(@class, 'create-action')]")
|
||||
add_button.click()
|
||||
return self._get_list_inputs(wrapper)[0]
|
||||
|
||||
def _get_list_inputs(self, list_wrapper):
|
||||
"""
|
||||
Finds nested input elements (useful for List and Dict fields)
|
||||
"""
|
||||
return list_wrapper.find_elements_by_xpath(".//input[@type='text']")
|
||||
|
||||
def _get_metadata_element(self, metadata_key):
|
||||
"""
|
||||
Gets metadata input element (a wrapper div for List and Dict fields)
|
||||
"""
|
||||
metadata_inputs = self.find_css(".metadata_entry .wrapper-comp-setting label.setting-label")
|
||||
target_label = [elem for elem in metadata_inputs if elem.text == metadata_key][0]
|
||||
label_for = target_label.get_attribute('for')
|
||||
return self.find_css("#" + label_for)[0]
|
||||
|
||||
def get_metadata_input(self, metadata_key):
|
||||
"""
|
||||
Gets input/select element for given field
|
||||
"""
|
||||
element = self._get_metadata_element(metadata_key)
|
||||
if element.tag_name == 'div':
|
||||
# List or Dict field - return first input
|
||||
# TODO support multiple values
|
||||
inputs = self._get_list_inputs(element)
|
||||
element = inputs[0] if inputs else None
|
||||
return element
|
||||
|
||||
|
||||
class StudioLibraryContainerXBlockWrapper(XBlockWrapper):
|
||||
"""
|
||||
Wraps :class:`.container.XBlockWrapper` for use with LibraryContent blocks
|
||||
"""
|
||||
url = None
|
||||
|
||||
@classmethod
|
||||
def from_xblock_wrapper(cls, xblock_wrapper):
|
||||
"""
|
||||
Factory method: creates :class:`.StudioLibraryContainerXBlockWrapper` from :class:`.container.XBlockWrapper`
|
||||
"""
|
||||
return cls(xblock_wrapper.browser, xblock_wrapper.locator)
|
||||
|
||||
@property
|
||||
def header_text(self):
|
||||
"""
|
||||
Gets library content text
|
||||
"""
|
||||
return self.get_body_paragraphs().first.text[0]
|
||||
|
||||
def get_body_paragraphs(self):
|
||||
"""
|
||||
Gets library content body paragraphs
|
||||
"""
|
||||
return self.q(css=self._bounded_selector(".xblock-message-area p"))
|
||||
|
||||
def refresh_children(self):
|
||||
"""
|
||||
Click "Update now..." button
|
||||
"""
|
||||
refresh_button = self.q(css=self._bounded_selector(".library-update-btn"))
|
||||
refresh_button.click()
|
||||
|
||||
169
common/test/acceptance/tests/lms/test_library.py
Normal file
169
common/test/acceptance/tests/lms/test_library.py
Normal file
@@ -0,0 +1,169 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
End-to-end tests for LibraryContent block in LMS
|
||||
"""
|
||||
import ddt
|
||||
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...pages.studio.auto_auth import AutoAuthPage
|
||||
from ...pages.studio.overview import CourseOutlinePage
|
||||
from ...pages.studio.library import StudioLibraryContentXBlockEditModal, 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'
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class LibraryContentTest(UniqueCourseTest):
|
||||
"""
|
||||
Test courseware.
|
||||
"""
|
||||
USERNAME = "STUDENT_TESTER"
|
||||
EMAIL = "student101@example.com"
|
||||
|
||||
STAFF_USERNAME = "STAFF_TESTER"
|
||||
STAFF_EMAIL = "staff101@example.com"
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up library, course and library content XBlock
|
||||
"""
|
||||
super(LibraryContentTest, 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.library_fixture.add_children(
|
||||
XBlockFixtureDesc("html", "Html1", data='html1'),
|
||||
XBlockFixtureDesc("html", "Html2", data='html2'),
|
||||
XBlockFixtureDesc("html", "Html3", data='html3'),
|
||||
)
|
||||
|
||||
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_libraries': [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 _refresh_library_content_children(self, count=1):
|
||||
"""
|
||||
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[0])
|
||||
modal = StudioLibraryContentXBlockEditModal(library_container_block.edit())
|
||||
modal.count = count
|
||||
library_container_block.save_settings()
|
||||
library_container_block.refresh_children()
|
||||
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.toggle_expand().unit(UNIT_NAME).go_to()
|
||||
|
||||
def _goto_library_block_page(self, block_id=None):
|
||||
"""
|
||||
Open library page in LMS
|
||||
"""
|
||||
self.courseware_page.visit()
|
||||
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)
|
||||
|
||||
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.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._refresh_library_content_children(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._refresh_library_content_children(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)
|
||||
@@ -109,8 +109,9 @@ class StudioLibraryTest(WebAppTest):
|
||||
"""
|
||||
Base class for all Studio library tests.
|
||||
"""
|
||||
as_staff = True
|
||||
|
||||
def setUp(self, is_staff=False): # pylint: disable=arguments-differ
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
"""
|
||||
Install a library with no content using a fixture.
|
||||
"""
|
||||
@@ -122,10 +123,11 @@ class StudioLibraryTest(WebAppTest):
|
||||
)
|
||||
self.populate_library_fixture(fixture)
|
||||
fixture.install()
|
||||
self.library_fixture = fixture
|
||||
self.library_info = fixture.library_info
|
||||
self.library_key = fixture.library_key
|
||||
self.user = fixture.user
|
||||
self.log_in(self.user, is_staff)
|
||||
self.log_in(self.user, self.as_staff)
|
||||
|
||||
def populate_library_fixture(self, library_fixture):
|
||||
"""
|
||||
|
||||
@@ -18,7 +18,7 @@ class LibraryEditPageTest(StudioLibraryTest):
|
||||
"""
|
||||
Ensure a library exists and navigate to the library edit page.
|
||||
"""
|
||||
super(LibraryEditPageTest, self).setUp(is_staff=True)
|
||||
super(LibraryEditPageTest, self).setUp()
|
||||
self.lib_page = LibraryPage(self.browser, self.library_key)
|
||||
self.lib_page.visit()
|
||||
self.lib_page.wait_until_ready()
|
||||
@@ -156,7 +156,7 @@ class LibraryNavigationTest(StudioLibraryTest):
|
||||
"""
|
||||
Ensure a library exists and navigate to the library edit page.
|
||||
"""
|
||||
super(LibraryNavigationTest, self).setUp(is_staff=True)
|
||||
super(LibraryNavigationTest, self).setUp()
|
||||
self.lib_page = LibraryPage(self.browser, self.library_key)
|
||||
self.lib_page.visit()
|
||||
self.lib_page.wait_until_ready()
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
Acceptance tests for Library Content in LMS
|
||||
"""
|
||||
import ddt
|
||||
from .base_studio_test import StudioLibraryTest, ContainerBase
|
||||
from ...pages.studio.library import StudioLibraryContentXBlockEditModal, StudioLibraryContainerXBlockWrapper
|
||||
from ...fixtures.course import XBlockFixtureDesc
|
||||
|
||||
SECTION_NAME = 'Test Section'
|
||||
SUBSECTION_NAME = 'Test Subsection'
|
||||
UNIT_NAME = 'Test Unit'
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class StudioLibraryContainerTest(ContainerBase, StudioLibraryTest):
|
||||
"""
|
||||
Test Library Content block in LMS
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Install library with some content and a course using fixtures
|
||||
"""
|
||||
super(StudioLibraryContainerTest, self).setUp()
|
||||
self.outline.visit()
|
||||
subsection = self.outline.section(SECTION_NAME).subsection(SUBSECTION_NAME)
|
||||
self.unit_page = subsection.toggle_expand().unit(UNIT_NAME).go_to()
|
||||
|
||||
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_libraries': [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(
|
||||
('library-v1:111+111', 1, True),
|
||||
('library-v1:edX+L104', 2, False),
|
||||
('library-v1:OtherX+IDDQD', 3, True),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_can_edit_metadata(self, library_key, 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_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0])
|
||||
edit_modal = StudioLibraryContentXBlockEditModal(library_container.edit())
|
||||
edit_modal.library_key = library_key
|
||||
edit_modal.count = max_count
|
||||
edit_modal.scored = scored
|
||||
|
||||
library_container.save_settings() # saving settings
|
||||
|
||||
# open edit window again to verify changes are persistent
|
||||
edit_modal = StudioLibraryContentXBlockEditModal(library_container.edit())
|
||||
self.assertEqual(edit_modal.library_key, library_key)
|
||||
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 set library key to none
|
||||
Then I can see that library content block is misconfigured
|
||||
"""
|
||||
expected_text = 'No library or filters configured. Press "Edit" to configure.'
|
||||
library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0])
|
||||
|
||||
# precondition check - assert library is configured before we remove it
|
||||
self.assertNotIn(expected_text, library_container.header_text)
|
||||
|
||||
edit_modal = StudioLibraryContentXBlockEditModal(library_container.edit())
|
||||
edit_modal.library_key = None
|
||||
|
||||
library_container.save_settings()
|
||||
|
||||
self.assertIn(expected_text, library_container.header_text)
|
||||
|
||||
@ddt.data(
|
||||
'library-v1:111+111',
|
||||
'library-v1:edX+L104',
|
||||
)
|
||||
def test_set_missing_library_shows_correct_label(self, library_key):
|
||||
"""
|
||||
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 set library key to non-existent library
|
||||
Then I can see that library content block is misconfigured
|
||||
"""
|
||||
expected_text = "Library is invalid, corrupt, or has been deleted."
|
||||
|
||||
library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0])
|
||||
|
||||
# precondition check - assert library is configured before we remove it
|
||||
self.assertNotIn(expected_text, library_container.header_text)
|
||||
|
||||
edit_modal = StudioLibraryContentXBlockEditModal(library_container.edit())
|
||||
edit_modal.library_key = library_key
|
||||
|
||||
library_container.save_settings()
|
||||
|
||||
self.assertIn(expected_text, library_container.header_text)
|
||||
Reference in New Issue
Block a user