Studio support for cohorted courseware

TNL-652
This commit is contained in:
Andy Armstrong
2014-12-11 10:05:00 -05:00
parent 206ea8caeb
commit 4fa33e25ed
47 changed files with 1121 additions and 255 deletions

View File

@@ -4,9 +4,9 @@ from utils import click_css
from selenium.webdriver.support.ui import Select
class ComponentEditorView(PageObject):
class BaseComponentEditorView(PageObject):
"""
A :class:`.PageObject` representing the rendered view of a component editor.
A base :class:`.PageObject` for the component and visibility editors.
This class assumes that the editor is our default editor as displayed for xmodules.
"""
@@ -18,7 +18,7 @@ class ComponentEditorView(PageObject):
browser (selenium.webdriver): The Selenium-controlled browser that this page is loaded in.
locator (str): The locator that identifies which xblock this :class:`.xblock-editor` relates to.
"""
super(ComponentEditorView, self).__init__(browser)
super(BaseComponentEditorView, self).__init__(browser)
self.locator = locator
def is_browser_on_page(self):
@@ -40,6 +40,23 @@ class ComponentEditorView(PageObject):
"""
return None
def save(self):
"""
Clicks save button.
"""
click_css(self, 'a.action-save')
def cancel(self):
"""
Clicks cancel button.
"""
click_css(self, 'a.action-cancel', require_notification=False)
class ComponentEditorView(BaseComponentEditorView):
"""
A :class:`.PageObject` representing the rendered view of a component editor.
"""
def get_setting_element(self, label):
"""
Returns the index of the setting entry with given label (display name) within the Settings modal.
@@ -86,14 +103,48 @@ class ComponentEditorView(PageObject):
else:
return None
def save(self):
"""
Clicks save button.
"""
click_css(self, 'a.action-save')
def cancel(self):
class ComponentVisibilityEditorView(BaseComponentEditorView):
"""
A :class:`.PageObject` representing the rendered view of a component visibility editor.
"""
OPTION_SELECTOR = '.modal-section-content li.field'
@property
def all_options(self):
"""
Clicks cancel button.
Return all visibility 'li' options.
"""
click_css(self, 'a.action-cancel', require_notification=False)
return self.q(css=self._bounded_selector(self.OPTION_SELECTOR)).results
@property
def selected_options(self):
"""
Return all selected visibility 'li' options.
"""
results = []
for option in self.all_options:
button = option.find_element_by_css_selector('input.input')
if button.is_selected():
results.append(option)
return results
def select_option(self, label_text, save=True):
"""
Click the first li which has a label matching `label_text`.
Arguments:
label_text (str): Text of a label accompanying the input
which should be clicked.
save (boolean): Whether the "save" button should be clicked
afterwards.
Returns:
bool: Whether the label was found and clicked.
"""
for option in self.all_options:
if label_text in option.text:
option.click()
if save:
self.save()
return True
return False

View File

@@ -152,6 +152,13 @@ class ContainerPage(PageObject):
"""
return self.q(css='.bit-publishing .wrapper-visibility .copy .inherited-from').visible
@property
def sidebar_visibility_message(self):
"""
Returns the text within the sidebar visibility section.
"""
return self.q(css='.bit-publishing .wrapper-visibility').first.text[0]
@property
def publish_action(self):
"""
@@ -243,7 +250,7 @@ class ContainerPage(PageObject):
"""
Clicks the "edit" button for the first component on the page.
"""
return _click_edit(self)
return _click_edit(self, '.edit-button', '.xblock-studio_view')
def add_missing_groups(self):
"""
@@ -282,6 +289,7 @@ class XBlockWrapper(PageObject):
url = None
BODY_SELECTOR = '.studio-xblock-wrapper'
NAME_SELECTOR = '.xblock-display-name'
VALIDATION_SELECTOR = '.xblock-message.validation'
COMPONENT_BUTTONS = {
'basic_tab': '.editor-tabs li.inner_tab_wrap:nth-child(1) > a',
'advanced_tab': '.editor-tabs li.inner_tab_wrap:nth-child(2) > a',
@@ -348,11 +356,11 @@ class XBlockWrapper(PageObject):
@property
def has_validation_message(self):
""" Is a validation warning/error/message shown? """
return self.q(css=self._bounded_selector('.xblock-message.validation')).present
return self.q(css=self._bounded_selector(self.VALIDATION_SELECTOR)).present
def _validation_paragraph(self, css_class):
""" Helper method to return the <p> element of a validation warning """
return self.q(css=self._bounded_selector('.xblock-message.validation p.{}'.format(css_class)))
return self.q(css=self._bounded_selector('{} p.{}'.format(self.VALIDATION_SELECTOR, css_class)))
@property
def has_validation_warning(self):
@@ -380,6 +388,10 @@ class XBlockWrapper(PageObject):
""" Get the text of the validation error. """
return self._validation_paragraph('error').text[0]
@property
def validation_error_messages(self):
return self.q(css=self._bounded_selector('{} .xblock-message-item.error'.format(self.VALIDATION_SELECTOR))).text
@property
# pylint: disable=invalid-name
def validation_not_configured_warning_text(self):
@@ -390,6 +402,10 @@ class XBlockWrapper(PageObject):
def preview_selector(self):
return self._bounded_selector('.xblock-student_view,.xblock-author_view')
@property
def has_group_visibility_set(self):
return self.q(css=self._bounded_selector('.wrapper-xblock.has-group-visibility-set')).is_present()
def go_to_container(self):
"""
Open the container page linked to by this xblock, and return
@@ -401,7 +417,13 @@ class XBlockWrapper(PageObject):
"""
Clicks the "edit" button for this xblock.
"""
return _click_edit(self, self._bounded_selector)
return _click_edit(self, '.edit-button', '.xblock-studio_view', self._bounded_selector)
def edit_visibility(self):
"""
Clicks the edit visibility button for this xblock.
"""
return _click_edit(self, '.visibility-button', '.xblock-visibility_view', self._bounded_selector)
def open_advanced_tab(self):
"""
@@ -478,13 +500,13 @@ class XBlockWrapper(PageObject):
return self.q(css=self._bounded_selector('span.message-text a')).first.text[0]
def _click_edit(page_object, bounded_selector=lambda(x): x):
def _click_edit(page_object, button_css, view_css, bounded_selector=lambda(x): x):
"""
Click on the first edit button found and wait for the Studio editor to be present.
Click on the first editing button found and wait for the Studio editor to be present.
"""
page_object.q(css=bounded_selector('.edit-button')).first.click()
page_object.q(css=bounded_selector(button_css)).first.click()
EmptyPromise(
lambda: page_object.q(css='.xblock-studio_view').present,
lambda: page_object.q(css=view_css).present,
'Wait for the Studio editor to be present'
).fulfill()