Commit f31475a2 by Ben McMorran Committed by cahrens

Add bokchoy tests for outline page

parent 327a97f7
...@@ -125,6 +125,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_ ...@@ -125,6 +125,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
// as it cannot visually effect the other sections. // as it cannot visually effect the other sections.
if (childCategory === 'chapter' && children && children.length > 1) { if (childCategory === 'chapter' && children && children.length > 1) {
childView.$el.remove(); childView.$el.remove();
children.splice(children.indexOf(childView.model), 1);
} else { } else {
this.refresh(); this.refresh();
} }
......
...@@ -22,7 +22,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views ...@@ -22,7 +22,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
}); });
this.nameEditor.render(); this.nameEditor.render();
if (this.options.action === 'new') { if (this.options.action === 'new') {
this.nameEditor.$('.xblock-field-value').click(); this.nameEditor.$('.xblock-field-value-edit').click();
} }
this.xblockView = new ContainerView({ this.xblockView = new ContainerView({
el: this.$('.wrapper-xblock'), el: this.$('.wrapper-xblock'),
......
...@@ -194,7 +194,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/ ...@@ -194,7 +194,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
} }
ViewUtils.setScrollOffset(locatorElement, scrollOffset); ViewUtils.setScrollOffset(locatorElement, scrollOffset);
if (editDisplayName) { if (editDisplayName) {
locatorElement.find('> .wrapper-xblock-header .xblock-field-value').click(); locatorElement.find('> .wrapper-xblock-header .xblock-field-value-edit').click();
} }
} }
this.initialState = null; this.initialState = null;
......
...@@ -8,7 +8,7 @@ from . import BASE_URL ...@@ -8,7 +8,7 @@ from . import BASE_URL
from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.action_chains import ActionChains
from utils import click_css, wait_for_notification from utils import click_css, wait_for_notification, confirm_prompt
class ContainerPage(PageObject): class ContainerPage(PageObject):
...@@ -16,6 +16,8 @@ class ContainerPage(PageObject): ...@@ -16,6 +16,8 @@ class ContainerPage(PageObject):
Container page in Studio Container page in Studio
""" """
NAME_SELECTOR = '.page-header-title' NAME_SELECTOR = '.page-header-title'
NAME_INPUT_SELECTOR = '.page-header .xblock-field-input'
NAME_FIELD_WRAPPER_SELECTOR = '.page-header .wrapper-xblock-field'
def __init__(self, browser, locator): def __init__(self, browser, locator):
super(ContainerPage, self).__init__(browser) super(ContainerPage, self).__init__(browser)
...@@ -134,7 +136,7 @@ class ContainerPage(PageObject): ...@@ -134,7 +136,7 @@ class ContainerPage(PageObject):
Discards draft changes (which will then re-render the page). Discards draft changes (which will then re-render the page).
""" """
click_css(self, 'a.action-discard', 0, require_notification=False) click_css(self, 'a.action-discard', 0, require_notification=False)
self.q(css='a.button.action-primary').first.click() confirm_prompt(self)
self.wait_for_ajax() self.wait_for_ajax()
def toggle_staff_lock(self): def toggle_staff_lock(self):
...@@ -149,7 +151,7 @@ class ContainerPage(PageObject): ...@@ -149,7 +151,7 @@ class ContainerPage(PageObject):
self.q(css='a.action-staff-lock').first.click() self.q(css='a.action-staff-lock').first.click()
else: else:
click_css(self, 'a.action-staff-lock', 0, require_notification=False) click_css(self, 'a.action-staff-lock', 0, require_notification=False)
self.q(css='a.button.action-primary').first.click() confirm_prompt(self)
self.wait_for_ajax() self.wait_for_ajax()
return not was_locked_initially return not was_locked_initially
...@@ -218,16 +220,8 @@ class ContainerPage(PageObject): ...@@ -218,16 +220,8 @@ class ContainerPage(PageObject):
""" """
# Click the delete button # Click the delete button
click_css(self, 'a.delete-button', source_index, require_notification=False) click_css(self, 'a.delete-button', source_index, require_notification=False)
# Wait for the warning prompt to appear
self.wait_for_element_visibility('#prompt-warning', 'Deletion warning prompt is visible')
# Make sure the delete button is there
confirmation_button_css = '#prompt-warning a.button.action-primary'
self.wait_for_element_visibility(confirmation_button_css, 'Confirmation dialog button is visible')
# Click the confirmation dialog button # Click the confirmation dialog button
click_css(self, confirmation_button_css, 0) confirm_prompt(self)
def edit(self): def edit(self):
""" """
...@@ -255,6 +249,12 @@ class ContainerPage(PageObject): ...@@ -255,6 +249,12 @@ class ContainerPage(PageObject):
""" """
return self.q(css=".xblock-message.information").first.text[0] return self.q(css=".xblock-message.information").first.text[0]
def is_inline_editing_display_name(self):
"""
Return whether this container's display name is in its editable form.
"""
return "is-editing" in self.q(css=self.NAME_FIELD_WRAPPER_SELECTOR).first.attrs("class")[0]
class XBlockWrapper(PageObject): class XBlockWrapper(PageObject):
""" """
......
...@@ -6,7 +6,7 @@ from bok_choy.promise import EmptyPromise ...@@ -6,7 +6,7 @@ from bok_choy.promise import EmptyPromise
from .course_page import CoursePage from .course_page import CoursePage
from .container import ContainerPage from .container import ContainerPage
from .utils import set_input_value_and_save from .utils import set_input_value_and_save, click_css, confirm_prompt
class CourseOutlineItem(object): class CourseOutlineItem(object):
...@@ -17,9 +17,13 @@ class CourseOutlineItem(object): ...@@ -17,9 +17,13 @@ class CourseOutlineItem(object):
EDIT_BUTTON_SELECTOR = '.xblock-title .xblock-field-value-edit' EDIT_BUTTON_SELECTOR = '.xblock-title .xblock-field-value-edit'
NAME_SELECTOR = '.xblock-title .xblock-field-value' NAME_SELECTOR = '.xblock-title .xblock-field-value'
NAME_INPUT_SELECTOR = '.xblock-title .xblock-field-input' NAME_INPUT_SELECTOR = '.xblock-title .xblock-field-input'
NAME_FIELD_WRAPPER_SELECTOR = '.xblock-title .wrapper-xblock-field'
def __repr__(self): def __repr__(self):
return "{}(<browser>, {!r})".format(self.__class__.__name__, self.locator) # CourseOutlineItem is also used as a mixin for CourseOutlinePage, which doesn't have a locator
# Check for the existence of a locator so that errors when navigating to the course outline page don't show up
# as errors in the repr method instead.
return "{}(<browser>, {!r})".format(self.__class__.__name__, self.locator if hasattr(self, 'locator') else None)
def _bounded_selector(self, selector): def _bounded_selector(self, selector):
""" """
...@@ -50,6 +54,14 @@ class CourseOutlineItem(object): ...@@ -50,6 +54,14 @@ class CourseOutlineItem(object):
set_input_value_and_save(self, self._bounded_selector(self.NAME_INPUT_SELECTOR), new_name) set_input_value_and_save(self, self._bounded_selector(self.NAME_INPUT_SELECTOR), new_name)
self.wait_for_ajax() self.wait_for_ajax()
def in_editable_form(self):
"""
Return whether this outline item's display name is in its editable form.
"""
return "is-editing" in self.q(
css=self._bounded_selector(self.NAME_FIELD_WRAPPER_SELECTOR)
)[0].get_attribute("class")
class CourseOutlineContainer(CourseOutlineItem): class CourseOutlineContainer(CourseOutlineItem):
""" """
...@@ -76,6 +88,15 @@ class CourseOutlineContainer(CourseOutlineItem): ...@@ -76,6 +88,15 @@ class CourseOutlineContainer(CourseOutlineItem):
).attrs('data-locator')[0] ).attrs('data-locator')[0]
) )
def children(self, child_class=None):
"""
Returns all the children page objects of class child_class.
"""
if not child_class:
child_class = self.CHILD_CLASS
return self.q(css=child_class.BODY_SELECTOR).map(
lambda el: child_class(self.browser, el.get_attribute('data-locator'))).results
def child_at(self, index, child_class=None): def child_at(self, index, child_class=None):
""" """
Returns the child at the specified index. Returns the child at the specified index.
...@@ -84,11 +105,47 @@ class CourseOutlineContainer(CourseOutlineItem): ...@@ -84,11 +105,47 @@ class CourseOutlineContainer(CourseOutlineItem):
if not child_class: if not child_class:
child_class = self.CHILD_CLASS child_class = self.CHILD_CLASS
return child_class( return self.children(child_class)[index]
self.browser,
self.q(css=child_class.BODY_SELECTOR).attrs('data-locator')[index] def add_child(self, require_notification=True):
"""
Adds a child to this xblock, waiting for notifications.
"""
click_css(
self,
self._bounded_selector(".add-xblock-component a.add-button"),
require_notification=require_notification,
) )
def toggle_expand(self):
"""
Toggle the expansion of this subsection.
"""
self.browser.execute_script("jQuery.fx.off = true;")
def subsection_expanded():
add_button = self.q(css=self._bounded_selector('> .add-xblock-component a.add-button')).first.results
return add_button and add_button[0].is_displayed()
currently_expanded = subsection_expanded()
self.q(css=self._bounded_selector('.ui-toggle-expansion')).first.click()
EmptyPromise(
lambda: subsection_expanded() != currently_expanded,
"Check that the container {} has been toggled".format(self.locator)
).fulfill()
return self
@property
def is_collapsed(self):
"""
Return whether this outline item is currently collapsed.
"""
return "collapsed" in self.q(css=self._bounded_selector('')).first.attrs("class")[0]
class CourseOutlineChild(PageObject, CourseOutlineItem): class CourseOutlineChild(PageObject, CourseOutlineItem):
""" """
...@@ -101,10 +158,17 @@ class CourseOutlineChild(PageObject, CourseOutlineItem): ...@@ -101,10 +158,17 @@ class CourseOutlineChild(PageObject, CourseOutlineItem):
def is_browser_on_page(self): def is_browser_on_page(self):
return self.q(css='{}[data-locator="{}"]'.format(self.BODY_SELECTOR, self.locator)).present return self.q(css='{}[data-locator="{}"]'.format(self.BODY_SELECTOR, self.locator)).present
def delete(self, cancel=False):
"""
Clicks the delete button, then cancels at the confirmation prompt if cancel is True.
"""
click_css(self, self._bounded_selector('.delete-button'), require_notification=False)
confirm_prompt(self, cancel)
class CourseOutlineUnit(CourseOutlineChild): class CourseOutlineUnit(CourseOutlineChild):
""" """
PageObject that wraps a unit link on the Studio Course Overview page. PageObject that wraps a unit link on the Studio Course Outline page.
""" """
url = None url = None
BODY_SELECTOR = '.outline-item-unit' BODY_SELECTOR = '.outline-item-unit'
...@@ -123,7 +187,7 @@ class CourseOutlineUnit(CourseOutlineChild): ...@@ -123,7 +187,7 @@ class CourseOutlineUnit(CourseOutlineChild):
class CourseOutlineSubsection(CourseOutlineChild, CourseOutlineContainer): class CourseOutlineSubsection(CourseOutlineChild, CourseOutlineContainer):
""" """
:class`.PageObject` that wraps a subsection block on the Studio Course Overview page. :class`.PageObject` that wraps a subsection block on the Studio Course Outline page.
""" """
url = None url = None
...@@ -136,31 +200,28 @@ class CourseOutlineSubsection(CourseOutlineChild, CourseOutlineContainer): ...@@ -136,31 +200,28 @@ class CourseOutlineSubsection(CourseOutlineChild, CourseOutlineContainer):
""" """
return self.child(title) return self.child(title)
def toggle_expand(self): def units(self):
""" """
Toggle the expansion of this subsection. Returns the units in this subsection.
""" """
self.browser.execute_script("jQuery.fx.off = true;") return self.children()
def subsection_expanded():
add_button = self.q(css=self._bounded_selector('.add-button')).first.results
return add_button and add_button[0].is_displayed()
currently_expanded = subsection_expanded()
self.q(css=self._bounded_selector('.ui-toggle-expansion')).first.click() def unit_at(self, index):
"""
EmptyPromise( Returns the CourseOutlineUnit at the specified index.
lambda: subsection_expanded() != currently_expanded, """
"Check that the subsection {} has been toggled".format(self.locator) return self.child_at(index)
).fulfill()
return self def add_unit(self):
"""
Adds a unit to this subsection
"""
self.add_child(require_notification=False)
class CourseOutlineSection(CourseOutlineChild, CourseOutlineContainer): class CourseOutlineSection(CourseOutlineChild, CourseOutlineContainer):
""" """
:class`.PageObject` that wraps a section block on the Studio Course Overview page. :class`.PageObject` that wraps a section block on the Studio Course Outline page.
""" """
url = None url = None
BODY_SELECTOR = '.outline-item-section' BODY_SELECTOR = '.outline-item-section'
...@@ -172,6 +233,33 @@ class CourseOutlineSection(CourseOutlineChild, CourseOutlineContainer): ...@@ -172,6 +233,33 @@ class CourseOutlineSection(CourseOutlineChild, CourseOutlineContainer):
""" """
return self.child(title) return self.child(title)
def subsections(self):
"""
Returns a list of the CourseOutlineSubsections of this section
"""
return self.children()
def subsection_at(self, index):
"""
Returns the CourseOutlineSubsection at the specified index.
"""
return self.child_at(index)
def add_subsection(self):
"""
Adds a subsection to this section
"""
self.add_child()
class ExpandCollapseLinkState:
"""
Represents the three states that the expand/collapse link can be in
"""
MISSING = 0
COLLAPSE = 1
EXPAND = 2
class CourseOutlinePage(CoursePage, CourseOutlineContainer): class CourseOutlinePage(CoursePage, CourseOutlineContainer):
""" """
...@@ -179,10 +267,19 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer): ...@@ -179,10 +267,19 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer):
""" """
url_path = "course" url_path = "course"
CHILD_CLASS = CourseOutlineSection CHILD_CLASS = CourseOutlineSection
EXPAND_COLLAPSE_CSS = '.toggle-button-expand-collapse'
BOTTOM_ADD_SECTION_BUTTON = '.course-outline > .add-xblock-component .add-button'
def is_browser_on_page(self): def is_browser_on_page(self):
return self.q(css='body.view-outline').present return self.q(css='body.view-outline').present
def view_live(self):
"""
Clicks the "View Live" link and switches to the new tab
"""
click_css(self, '.view-live-button', require_notification=False)
self.browser.switch_to_window(self.browser.window_handles[-1])
def section(self, title): def section(self, title):
""" """
Return the :class:`.CourseOutlineSection` with the title `title`. Return the :class:`.CourseOutlineSection` with the title `title`.
...@@ -194,7 +291,7 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer): ...@@ -194,7 +291,7 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer):
Returns the :class:`.CourseOutlineSection` at the specified index. Returns the :class:`.CourseOutlineSection` at the specified index.
""" """
return self.child_at(index) return self.child_at(index)
def click_section_name(self, parent_css=''): def click_section_name(self, parent_css=''):
""" """
Find and click on first section name in course outline Find and click on first section name in course outline
...@@ -229,3 +326,54 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer): ...@@ -229,3 +326,54 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer):
Open release date edit modal of first section in course outline Open release date edit modal of first section in course outline
""" """
self.q(css='div.section-published-date a.edit-release-date').first.click() self.q(css='div.section-published-date a.edit-release-date').first.click()
def sections(self):
"""
Returns the sections of this course outline page.
"""
return self.children()
def add_section_from_top_button(self):
"""
Clicks the button for adding a section which resides at the top of the screen.
"""
click_css(self, '.wrapper-mast nav.nav-actions .add-button')
def add_section_from_bottom_button(self):
"""
Clicks the button for adding a section which resides at the bottom of the screen.
"""
click_css(self, self.BOTTOM_ADD_SECTION_BUTTON)
def toggle_expand_collapse(self):
"""
Toggles whether all sections are expanded or collapsed
"""
self.q(css=self.EXPAND_COLLAPSE_CSS).click()
@property
def bottom_add_section_button(self):
"""
Returns the query representing the bottom add section button.
"""
return self.q(css=self.BOTTOM_ADD_SECTION_BUTTON).first
@property
def has_no_content_message(self):
"""
Returns true if a message informing the user that the course has no content is visible
"""
return self.q(css='.course-outline .no-content').is_present()
@property
def expand_collapse_link_state(self):
"""
Returns the current state of the expand/collapse link
"""
link = self.q(css=self.EXPAND_COLLAPSE_CSS)[0]
if not link.is_displayed():
return ExpandCollapseLinkState.MISSING
elif "collapse-all" in link.get_attribute("class"):
return ExpandCollapseLinkState.COLLAPSE
else:
return ExpandCollapseLinkState.EXPAND
...@@ -139,3 +139,14 @@ def set_input_value_and_save(page, css, value): ...@@ -139,3 +139,14 @@ def set_input_value_and_save(page, css, value):
action = action.send_keys(Keys.BACKSPACE) action = action.send_keys(Keys.BACKSPACE)
# Send the new text, then hit the enter key so that the change event is triggered). # Send the new text, then hit the enter key so that the change event is triggered).
action.send_keys(value).send_keys(Keys.ENTER).perform() action.send_keys(value).send_keys(Keys.ENTER).perform()
def confirm_prompt(page, cancel=False):
"""
Ensures that a modal prompt and confirmation button are visible, then clicks the button. The prompt is canceled iff
cancel is True.
"""
page.wait_for_element_visibility('.prompt', 'Prompt is visible')
confirmation_button_css = '.prompt .action-' + ('secondary' if cancel else 'primary')
page.wait_for_element_visibility(confirmation_button_css, 'Confirmation button is visible')
click_css(page, confirmation_button_css, require_notification=(not cancel))
...@@ -6,18 +6,17 @@ displaying containers within units. ...@@ -6,18 +6,17 @@ displaying containers within units.
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from ..pages.studio.overview import CourseOutlinePage from ..pages.studio.overview import CourseOutlinePage
from ..fixtures.course import XBlockFixtureDesc
from ..fixtures.course import XBlockFixtureDesc
from ..pages.studio.component_editor import ComponentEditorView from ..pages.studio.component_editor import ComponentEditorView
from ..pages.studio.html_component_editor import HtmlComponentEditorView from ..pages.studio.html_component_editor import HtmlComponentEditorView
from ..pages.studio.utils import add_discussion from ..pages.studio.utils import add_discussion
from ..pages.lms.courseware import CoursewarePage from ..pages.lms.courseware import CoursewarePage
from ..pages.lms.staff_view import StaffPage from ..pages.lms.staff_view import StaffPage
from unittest import skip
from acceptance.tests.base_studio_test import StudioCourseTest
import datetime import datetime
from bok_choy.promise import Promise, EmptyPromise from bok_choy.promise import Promise, EmptyPromise
from acceptance.tests.base_studio_test import StudioCourseTest
@attr('shard_1') @attr('shard_1')
...@@ -388,23 +387,17 @@ class UnitPublishingTest(ContainerBase): ...@@ -388,23 +387,17 @@ class UnitPublishingTest(ContainerBase):
LAST_PUBLISHED = 'Last published' LAST_PUBLISHED = 'Last published'
LAST_SAVED = 'Draft saved on' LAST_SAVED = 'Draft saved on'
def setup_fixtures(self): def populate_course_fixture(self, course_fixture):
""" """
Sets up a course structure with a unit and a single HTML child. Sets up a course structure with a unit and a single HTML child.
""" """
self.html_content = '<p><strong>Body of HTML Unit.</strong></p>' self.html_content = '<p><strong>Body of HTML Unit.</strong></p>'
self.courseware = CoursewarePage(self.browser, self.course_id) self.courseware = CoursewarePage(self.browser, self.course_id)
course_fix = CourseFixture(
self.course_info['org'],
self.course_info['number'],
self.course_info['run'],
self.course_info['display_name']
)
past_start_date = datetime.datetime(1974, 6, 22) past_start_date = datetime.datetime(1974, 6, 22)
self.past_start_date_text = "Jun 22, 1974 at 00:00 UTC" self.past_start_date_text = "Jun 22, 1974 at 00:00 UTC"
course_fix.add_children( course_fixture.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children(
...@@ -426,9 +419,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -426,9 +419,7 @@ class UnitPublishingTest(ContainerBase):
) )
) )
) )
).install() )
self.user = course_fix.user
def test_publishing(self): def test_publishing(self):
""" """
...@@ -495,7 +486,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -495,7 +486,7 @@ class UnitPublishingTest(ContainerBase):
Then I see the published content in LMS Then I see the published content in LMS
""" """
unit = self.go_to_unit_page() unit = self.go_to_unit_page()
unit.view_published_version() self._view_published_version(unit)
self._verify_components_visible(['html']) self._verify_components_visible(['html'])
def test_view_live_changes(self): def test_view_live_changes(self):
...@@ -510,7 +501,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -510,7 +501,7 @@ class UnitPublishingTest(ContainerBase):
""" """
unit = self.go_to_unit_page() unit = self.go_to_unit_page()
add_discussion(unit) add_discussion(unit)
unit.view_published_version() self._view_published_version(unit)
self._verify_components_visible(['html']) self._verify_components_visible(['html'])
self.assertEqual(self.html_content, self.courseware.xblock_component_html_content(0)) self.assertEqual(self.html_content, self.courseware.xblock_component_html_content(0))
...@@ -527,7 +518,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -527,7 +518,7 @@ class UnitPublishingTest(ContainerBase):
unit = self.go_to_unit_page() unit = self.go_to_unit_page()
add_discussion(unit) add_discussion(unit)
unit.publish_action.click() unit.publish_action.click()
unit.view_published_version() self._view_published_version(unit)
self._verify_components_visible(['html', 'discussion']) self._verify_components_visible(['html', 'discussion'])
def test_initially_unlocked_visible_to_students(self): def test_initially_unlocked_visible_to_students(self):
...@@ -547,7 +538,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -547,7 +538,7 @@ class UnitPublishingTest(ContainerBase):
self._verify_release_date_info( self._verify_release_date_info(
unit, self.RELEASE_TITLE_RELEASED, self.past_start_date_text + ' with Section "Unlocked Section"' unit, self.RELEASE_TITLE_RELEASED, self.past_start_date_text + ' with Section "Unlocked Section"'
) )
unit.view_published_version() self._view_published_version(unit)
self._verify_student_view_visible(['problem']) self._verify_student_view_visible(['problem'])
def test_locked_visible_to_staff_only(self): def test_locked_visible_to_staff_only(self):
...@@ -567,7 +558,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -567,7 +558,7 @@ class UnitPublishingTest(ContainerBase):
self.assertTrue(checked) self.assertTrue(checked)
self.assertFalse(unit.currently_visible_to_students) self.assertFalse(unit.currently_visible_to_students)
self._verify_publish_title(unit, self.LOCKED_STATUS) self._verify_publish_title(unit, self.LOCKED_STATUS)
unit.view_published_version() self._view_published_version(unit)
# Will initially be in staff view, locked component should be visible. # Will initially be in staff view, locked component should be visible.
self._verify_components_visible(['problem']) self._verify_components_visible(['problem'])
# Switch to student view and verify not visible # Switch to student view and verify not visible
...@@ -591,7 +582,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -591,7 +582,7 @@ class UnitPublishingTest(ContainerBase):
unit, self.RELEASE_TITLE_RELEASED, unit, self.RELEASE_TITLE_RELEASED,
self.past_start_date_text + ' with Subsection "Subsection With Locked Unit"' self.past_start_date_text + ' with Subsection "Subsection With Locked Unit"'
) )
unit.view_published_version() self._view_published_version(unit)
self._verify_student_view_locked() self._verify_student_view_locked()
def test_unlocked_visible_to_all(self): def test_unlocked_visible_to_all(self):
...@@ -611,7 +602,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -611,7 +602,7 @@ class UnitPublishingTest(ContainerBase):
self.assertFalse(checked) self.assertFalse(checked)
self._verify_publish_title(unit, self.PUBLISHED_STATUS) self._verify_publish_title(unit, self.PUBLISHED_STATUS)
self.assertTrue(unit.currently_visible_to_students) self.assertTrue(unit.currently_visible_to_students)
unit.view_published_version() self._view_published_version(unit)
# Will initially be in staff view, components always visible. # Will initially be in staff view, components always visible.
self._verify_components_visible(['discussion']) self._verify_components_visible(['discussion'])
# Switch to student view and verify visible. # Switch to student view and verify visible.
...@@ -641,7 +632,7 @@ class UnitPublishingTest(ContainerBase): ...@@ -641,7 +632,7 @@ class UnitPublishingTest(ContainerBase):
unit.publish_action.click() unit.publish_action.click()
unit.wait_for_ajax() unit.wait_for_ajax()
self._verify_publish_title(unit, self.PUBLISHED_STATUS) self._verify_publish_title(unit, self.PUBLISHED_STATUS)
unit.view_published_version() self._view_published_version(unit)
self.assertTrue(modified_content in self.courseware.xblock_component_html_content(0)) self.assertTrue(modified_content in self.courseware.xblock_component_html_content(0))
def test_delete_child_in_published_unit(self): def test_delete_child_in_published_unit(self):
...@@ -662,9 +653,16 @@ class UnitPublishingTest(ContainerBase): ...@@ -662,9 +653,16 @@ class UnitPublishingTest(ContainerBase):
unit.publish_action.click() unit.publish_action.click()
unit.wait_for_ajax() unit.wait_for_ajax()
self._verify_publish_title(unit, self.PUBLISHED_STATUS) self._verify_publish_title(unit, self.PUBLISHED_STATUS)
unit.view_published_version() self._view_published_version(unit)
self.assertEqual(0, self.courseware.num_xblock_components) self.assertEqual(0, self.courseware.num_xblock_components)
def _view_published_version(self, unit):
"""
Goes to the published version, then waits for the browser to load the page.
"""
unit.view_published_version()
self.courseware.wait_for_page()
def _verify_and_return_staff_page(self): def _verify_and_return_staff_page(self):
""" """
Verifies that the browser is on the staff page and returns a StaffPage. Verifies that the browser is on the staff page and returns a StaffPage.
......
...@@ -113,57 +113,6 @@ class CoursePagesTest(StudioCourseTest): ...@@ -113,57 +113,6 @@ class CoursePagesTest(StudioCourseTest):
page.visit() page.visit()
@attr('shard_1')
class CourseSectionTest(StudioCourseTest):
"""
Tests that verify the sections name editable only inside headers in Studio Course Outline that you can get to
when logged in and have a course.
"""
COURSE_ID_SEPARATOR = "."
def setUp(self):
"""
Install a course with no content using a fixture.
"""
super(CourseSectionTest, self).setUp()
self.course_outline_page = CourseOutlinePage(
self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
)
self.course_outline_page.visit()
def populate_course_fixture(self, course_fixture):
""" Populates the course fixture with a test section """
course_fixture.add_children(
XBlockFixtureDesc('chapter', 'Test Section')
)
def test_section_name_editable_in_course_outline(self):
"""
Check that section name is editable on course outline page.
"""
new_name = u"Test Section New"
section = self.course_outline_page.section_at(0)
self.assertEqual(section.name, u"Test Section")
section.change_name(new_name)
self.browser.refresh()
self.assertEqual(section.name, new_name)
# TODO: re-enable when release date support is added back
# def test_section_name_not_editable_inside_modal(self):
# """
# Check that section name is not editable inside "Section Release Date" modal on course outline page.
# """
# parent_css='div.modal-window'
# self.course_outline_page.click_release_date()
# section_name = self.course_outline_page.get_section_name(parent_css)[0]
# self.assertEqual(section_name, '"Test Section"')
# self.course_outline_page.click_section_name(parent_css)
# section_name_edit_form = self.course_outline_page.section_name_edit_form_present(parent_css)
# self.assertFalse(section_name_edit_form)
@attr('shard_1')
class DiscussionPreviewTest(StudioCourseTest): class DiscussionPreviewTest(StudioCourseTest):
""" """
Tests that Inline Discussions are rendered with a custom preview in Studio Tests that Inline Discussions are rendered with a custom preview in Studio
......
"""
Acceptance tests for studio related to the outline page.
"""
from bok_choy.promise import EmptyPromise
from ..pages.studio.overview import CourseOutlinePage, ContainerPage, ExpandCollapseLinkState
from ..pages.lms.courseware import CoursewarePage
from ..fixtures.course import XBlockFixtureDesc
from acceptance.tests.base_studio_test import StudioCourseTest
class CourseOutlineTest(StudioCourseTest):
"""
Base class for all course outline tests
"""
COURSE_ID_SEPARATOR = "."
def setUp(self):
"""
Install a course with no content using a fixture.
"""
super(CourseOutlineTest, self).setUp()
self.course_outline_page = CourseOutlinePage(
self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
)
def populate_course_fixture(self, course_fixture):
""" Install a course with sections/problems, tabs, updates, and handouts """
course_fixture.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc('html', 'Test HTML Component'),
XBlockFixtureDesc('discussion', 'Test Discussion Component')
)
)
)
)
class EditNamesTest(CourseOutlineTest):
"""
Feature: Click-to-edit section/subsection names
"""
__test__ = True
def set_name_and_verify(self, item, old_name, new_name, expected_name):
"""
Changes the display name of item from old_name to new_name, then verifies that its value is expected_name.
"""
self.assertEqual(item.name, old_name)
item.change_name(new_name)
self.assertFalse(item.in_editable_form())
self.assertEqual(item.name, expected_name)
def test_edit_section_name(self):
"""
Scenario: Click-to-edit section name
Given that I have created a section
When I click on the name of section
Then the section name becomes editable
And given that I have edited the section name
When I click outside of the edited section name
Then the section name saves
And becomes non-editable
"""
self.course_outline_page.visit()
self.set_name_and_verify(
self.course_outline_page.section_at(0),
'Test Section',
'Changed',
'Changed'
)
def test_edit_subsection_name(self):
"""
Scenario: Click-to-edit subsection name
Given that I have created a subsection
When I click on the name of subsection
Then the subsection name becomes editable
And given that I have edited the subsection name
When I click outside of the edited subsection name
Then the subsection name saves
And becomes non-editable
"""
self.course_outline_page.visit()
self.set_name_and_verify(
self.course_outline_page.section_at(0).subsection_at(0),
'Test Subsection',
'Changed',
'Changed'
)
def test_edit_empty_section_name(self):
"""
Scenario: Click-to-edit section name, enter empty name
Given that I have created a section
And I have clicked to edit the name of the section
And I have entered an empty section name
When I click outside of the edited section name
Then the section name does not change
And becomes non-editable
"""
self.course_outline_page.visit()
self.set_name_and_verify(
self.course_outline_page.section_at(0),
'Test Section',
'',
'Test Section'
)
def test_edit_empty_subsection_name(self):
"""
Scenario: Click-to-edit subsection name, enter empty name
Given that I have created a subsection
And I have clicked to edit the name of the subsection
And I have entered an empty subsection name
When I click outside of the edited subsection name
Then the subsection name does not change
And becomes non-editable
"""
self.course_outline_page.visit()
self.set_name_and_verify(
self.course_outline_page.section_at(0).subsection_at(0),
'Test Subsection',
'',
'Test Subsection'
)
class CreateSectionsTest(CourseOutlineTest):
"""
Feature: Create new sections/subsections/units
"""
__test__ = True
def populate_course_fixture(self, course_fixture):
""" Start with a completely empty course to easily test adding things to it """
pass
def test_create_new_section_from_top_button(self):
"""
Scenario: Create new section from button at top of page
Given that I am on the course outline
When I click the "+ Add section" button at the top of the page
Then I see a new section added to the bottom of the page
And the display name is in its editable form.
"""
self.course_outline_page.visit()
self.course_outline_page.add_section_from_top_button()
self.assertEqual(len(self.course_outline_page.sections()), 1)
self.assertTrue(self.course_outline_page.section_at(0).in_editable_form())
def test_create_new_section_from_bottom_button(self):
"""
Scenario: Create new section from button at bottom of page
Given that I am on the course outline
When I click the "+ Add section" button at the bottom of the page
Then I see a new section added to the bottom of the page
And the display name is in its editable form.
"""
self.course_outline_page.visit()
self.course_outline_page.add_section_from_bottom_button()
self.assertEqual(len(self.course_outline_page.sections()), 1)
self.assertTrue(self.course_outline_page.section_at(0).in_editable_form())
def test_create_new_subsection(self):
"""
Scenario: Create new subsection
Given that I have created a section
When I click the "+ Add subsection" button in that section
Then I see a new subsection added to the bottom of the section
And the display name is in its editable form.
"""
self.course_outline_page.visit()
self.course_outline_page.add_section_from_top_button()
self.assertEqual(len(self.course_outline_page.sections()), 1)
self.course_outline_page.section_at(0).add_subsection()
subsections = self.course_outline_page.section_at(0).subsections()
self.assertEqual(len(subsections), 1)
self.assertTrue(subsections[0].in_editable_form())
def test_create_new_unit(self):
"""
Scenario: Create new unit
Given that I have created a section
And that I have created a subsection within that section
When I click the "+ Add unit" button in that subsection
Then I am redirected to a New Unit page
And the display name is in its editable form.
"""
self.course_outline_page.visit()
self.course_outline_page.add_section_from_top_button()
self.assertEqual(len(self.course_outline_page.sections()), 1)
self.course_outline_page.section_at(0).add_subsection()
self.assertEqual(len(self.course_outline_page.section_at(0).subsections()), 1)
self.course_outline_page.section_at(0).subsection_at(0).add_unit()
unit_page = ContainerPage(self.browser, None)
EmptyPromise(unit_page.is_browser_on_page, 'Browser is on the unit page').fulfill()
self.assertTrue(unit_page.is_inline_editing_display_name())
class DeleteContentTest(CourseOutlineTest):
"""
Feature: Deleting sections/subsections/units
"""
__test__ = True
def test_delete_section(self):
"""
Scenario: Delete section
Given that I am on the course outline
When I click the delete button for a section on the course outline
Then I should receive a confirmation message, asking me if I really want to delete the section
When I click "Yes, I want to delete this component"
Then the confirmation message should close
And the section should immediately be deleted from the course outline
"""
self.course_outline_page.visit()
self.assertEqual(len(self.course_outline_page.sections()), 1)
self.course_outline_page.section_at(0).delete()
self.assertEqual(len(self.course_outline_page.sections()), 0)
def test_cancel_delete_section(self):
"""
Scenario: Cancel delete of section
Given that I clicked the delte button for a section on the course outline
And I received a confirmation message, asking me if I really want to delete the component
When I click "Cancel"
Then the confirmation message should close
And the section should remain in the course outline
"""
self.course_outline_page.visit()
self.assertEqual(len(self.course_outline_page.sections()), 1)
self.course_outline_page.section_at(0).delete(cancel=True)
self.assertEqual(len(self.course_outline_page.sections()), 1)
def test_delete_subsection(self):
"""
Scenario: Delete subsection
Given that I am on the course outline
When I click the delete button for a subsection on the course outline
Then I should receive a confirmation message, asking me if I really want to delete the subsection
When I click "Yes, I want to delete this component"
Then the confiramtion message should close
And the subsection should immediately be deleted from the course outline
"""
self.course_outline_page.visit()
self.assertEqual(len(self.course_outline_page.section_at(0).subsections()), 1)
self.course_outline_page.section_at(0).subsection_at(0).delete()
self.assertEqual(len(self.course_outline_page.section_at(0).subsections()), 0)
def test_cancel_delete_subsection(self):
"""
Scenario: Cancel delete of subsection
Given that I clicked the delete button for a subsection on the course outline
And I received a confirmation message, asking me if I really want to delete the subsection
When I click "cancel"
Then the confirmation message should close
And the subsection should remain in the course outline
"""
self.course_outline_page.visit()
self.assertEqual(len(self.course_outline_page.section_at(0).subsections()), 1)
self.course_outline_page.section_at(0).subsection_at(0).delete(cancel=True)
self.assertEqual(len(self.course_outline_page.section_at(0).subsections()), 1)
def test_delete_unit(self):
"""
Scenario: Delete unit
Given that I am on the course outline
When I click the delete button for a unit on the course outline
Then I should receive a confirmation message, asking me if I really want to delete the unit
When I click "Yes, I want to delete this unit"
Then the confirmation message should close
And the unit should immediately be deleted from the course outline
"""
self.course_outline_page.visit()
self.course_outline_page.section_at(0).subsection_at(0).toggle_expand()
self.assertEqual(len(self.course_outline_page.section_at(0).subsection_at(0).units()), 1)
self.course_outline_page.section_at(0).subsection_at(0).unit_at(0).delete()
self.assertEqual(len(self.course_outline_page.section_at(0).subsection_at(0).units()), 0)
def test_cancel_delete_unit(self):
"""
Scenario: Cancel delete of unit
Given that I clicked the delete button for a unit on the course outline
And I received a confirmation message, asking me if I really want to delete the unit
When I click "Cancel"
Then the confirmation message should close
And the unit should remain in the course outline
"""
self.course_outline_page.visit()
self.course_outline_page.section_at(0).subsection_at(0).toggle_expand()
self.assertEqual(len(self.course_outline_page.section_at(0).subsection_at(0).units()), 1)
self.course_outline_page.section_at(0).subsection_at(0).unit_at(0).delete(cancel=True)
self.assertEqual(len(self.course_outline_page.section_at(0).subsection_at(0).units()), 1)
def test_delete_all_no_content_message(self):
"""
Scenario: Delete all sections/subsections/units in a course, "no content" message should appear
Given that I delete all sections, subsections, and units in a course
When I visit the course outline
Then I will see a message that says, "You haven't added any content to this course yet"
Add see a + Add Section button
"""
self.course_outline_page.visit()
self.assertFalse(self.course_outline_page.has_no_content_message)
self.course_outline_page.section_at(0).delete()
self.assertEqual(len(self.course_outline_page.sections()), 0)
self.assertTrue(self.course_outline_page.has_no_content_message)
class ExpandCollapseMultipleSectionsTest(CourseOutlineTest):
"""
Feature: Courses with multiple sections can expand and collapse all sections.
"""
__test__ = True
def populate_course_fixture(self, course_fixture):
""" Start with a course with two sections """
course_fixture.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
XBlockFixtureDesc('vertical', 'Test Unit')
)
),
XBlockFixtureDesc('chapter', 'Test Section 2').add_children(
XBlockFixtureDesc('sequential', 'Test Subsection 2').add_children(
XBlockFixtureDesc('vertical', 'Test Unit 2')
)
)
)
def verify_all_sections(self, collapsed):
"""
Verifies that all sections are collapsed if collapsed is True, otherwise all expanded.
"""
for section in self.course_outline_page.sections():
self.assertEqual(collapsed, section.is_collapsed)
def toggle_all_sections(self):
"""
Toggles the expand collapse state of all sections.
"""
for section in self.course_outline_page.sections():
section.toggle_expand()
def test_expanded_by_default(self):
"""
Scenario: The default layout for the outline page is to show sections in expanded view
Given I have a course with sections
When I navigate to the course outline page
Then I see the "Collapse All Sections" link
And all sections are expanded
"""
self.course_outline_page.visit()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.COLLAPSE)
self.verify_all_sections(collapsed=False)
def test_no_expand_link_for_empty_course(self):
"""
Scenario: Collapse link is removed after last section of a course is deleted
Given I have a course with multiple sections
And I navigate to the course outline page
When I will confirm all alerts
And I press the "section" delete icon
Then I do not see the "Collapse All Sections" link
And I will see a message that says "You haven't added any content to this course yet"
"""
self.course_outline_page.visit()
for section in self.course_outline_page.sections():
section.delete()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.MISSING)
self.assertTrue(self.course_outline_page.has_no_content_message)
def test_collapse_all_when_all_expanded(self):
"""
Scenario: Collapse all sections when all sections are expanded
Given I navigate to the outline page of a course with sections
And all sections are expanded
When I click the "Collapse All Sections" link
Then I see the "Expand All Sections" link
And all sections are collapsed
"""
self.course_outline_page.visit()
self.verify_all_sections(collapsed=False)
self.course_outline_page.toggle_expand_collapse()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.EXPAND)
self.verify_all_sections(collapsed=True)
def test_collapse_all_when_some_expanded(self):
"""
Scenario: Collapsing all sections when 1 or more sections are already collapsed
Given I navigate to the outline page of a course with sections
And all sections are expanded
When I collapse the first section
And I click the "Collapse All Sections" link
Then I see the "Expand All Sections" link
And all sections are collapsed
"""
self.course_outline_page.visit()
self.verify_all_sections(collapsed=False)
self.course_outline_page.section_at(0).toggle_expand()
self.course_outline_page.toggle_expand_collapse()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.EXPAND)
self.verify_all_sections(collapsed=True)
def test_expand_all_when_all_collapsed(self):
"""
Scenario: Expanding all sections when all sections are collapsed
Given I navigate to the outline page of a course with multiple sections
And I click the "Collapse All Sections" link
When I click the "Expand All Sections" link
Then I see the "Collapse All Sections" link
And all sections are expanded
"""
self.course_outline_page.visit()
self.course_outline_page.toggle_expand_collapse()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.EXPAND)
self.course_outline_page.toggle_expand_collapse()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.COLLAPSE)
self.verify_all_sections(collapsed=False)
def test_expand_all_when_some_collapsed(self):
"""
Scenario: Expanding all sections when 1 or more sections are already expanded
Given I navigate to the outline page of a course with multiple sections
And I click the "Collapse All Sections" link
When I expand the first section
And I click the "Expand All Sections" link
Then I see the "Collapse All Sections" link
And all sections are expanded
"""
self.course_outline_page.visit()
self.course_outline_page.toggle_expand_collapse()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.EXPAND)
self.course_outline_page.section_at(0).toggle_expand()
self.course_outline_page.toggle_expand_collapse()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.COLLAPSE)
self.verify_all_sections(collapsed=False)
class ExpandCollapseSingleSectionTest(CourseOutlineTest):
"""
Feature: Courses with a single section can expand and collapse all sections.
"""
__test__ = True
def test_no_expand_link_for_empty_course(self):
"""
Scenario: Collapse link is removed after last section of a course is deleted
Given I have a course with one section
And I navigate to the course outline page
When I will confirm all alerts
And I press the "section" delete icon
Then I do not see the "Collapse All Sections" link
And I will see a message that says "You haven't added any content to this course yet"
"""
self.course_outline_page.visit()
self.course_outline_page.section_at(0).delete()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.MISSING)
self.assertTrue(self.course_outline_page.has_no_content_message)
class ExpandCollapseEmptyTest(CourseOutlineTest):
"""
Feature: Courses with no sections initially can expand and collapse all sections after addition.
"""
__test__ = True
def populate_course_fixture(self, course_fixture):
""" Start with an empty course """
pass
def test_no_expand_link_for_empty_course(self):
"""
Scenario: Expand/collapse for a course with no sections
Given I have a course with no sections
When I navigate to the course outline page
Then I do not see the "Collapse All Sections" link
"""
self.course_outline_page.visit()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.MISSING)
def test_link_appears_after_section_creation(self):
"""
Scenario: Collapse link appears after creating first section of a course
Given I have a course with no sections
When I navigate to the course outline page
And I add a section
Then I see the "Collapse All Sections" link
And all sections are expanded
"""
self.course_outline_page.visit()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.MISSING)
self.course_outline_page.add_section_from_top_button()
self.assertEquals(self.course_outline_page.expand_collapse_link_state, ExpandCollapseLinkState.COLLAPSE)
self.assertFalse(self.course_outline_page.section_at(0).is_collapsed)
class DefaultStatesEmptyTest(CourseOutlineTest):
"""
Feature: Misc course outline default states/actions when starting with an empty course
"""
__test__ = True
def populate_course_fixture(self, course_fixture):
""" Start with an empty course """
pass
def test_empty_course_message(self):
"""
Scenario: Empty course state
Given that I am in a course with no sections, subsections, nor units
When I visit the course outline
Then I will see a message that says "You haven't added any content to this course yet"
And see a + Add Section button
"""
self.course_outline_page.visit()
self.assertTrue(self.course_outline_page.has_no_content_message)
self.assertTrue(self.course_outline_page.bottom_add_section_button.is_present())
class DefaultStatesContentTest(CourseOutlineTest):
"""
Feature: Misc course outline default states/actions when starting with a course with content
"""
__test__ = True
def test_view_live(self):
"""
Scenario: View Live version from course outline
Given that I am on the course outline
When I click the "View Live" button
Then a new tab will open to the course on the LMS
"""
self.course_outline_page.visit()
self.course_outline_page.view_live()
courseware = CoursewarePage(self.browser, self.course_id)
courseware.wait_for_page()
self.assertEqual(courseware.num_xblock_components, 2)
self.assertEqual(courseware.xblock_component_type(0), 'html')
self.assertEqual(courseware.xblock_component_type(1), 'discussion')
class UnitNavigationTest(CourseOutlineTest):
"""
Feature: Navigate to units
"""
__test__ = True
def test_navigate_to_unit(self):
"""
Scenario: Click unit name to navigate to unit page
Given that I have expanded a section/subsection so I can see unit names
When I click on a unit name
Then I will be taken to the appropriate unit page
"""
self.course_outline_page.visit()
self.course_outline_page.section_at(0).subsection_at(0).toggle_expand()
unit = self.course_outline_page.section_at(0).subsection_at(0).unit_at(0).go_to()
self.assertTrue(unit.is_browser_on_page)
...@@ -65,30 +65,22 @@ class SplitTestMixin(object): ...@@ -65,30 +65,22 @@ class SplitTestMixin(object):
Promise(missing_groups_button_not_present, "Add missing groups button should not be showing.").fulfill() Promise(missing_groups_button_not_present, "Add missing groups button should not be showing.").fulfill()
@attr('shard_1') @attr('shard_1')
class SplitTest(ContainerBase, SplitTestMixin): class SplitTest(ContainerBase):
""" """
Tests for creating and editing split test instances in Studio. Tests for creating and editing split test instances in Studio.
""" """
__test__ = True __test__ = True
def setUp(self):
super(SplitTest, self).setUp()
# This line should be called once courseFixture is installed
self.course_fixture._update_xblock(self.course_fixture._course_location, {
"metadata": {
u"user_partitions": [
UserPartition(0, 'Configuration alpha,beta', 'first', [Group("0", 'alpha'), Group("1", 'beta')]).to_json(),
UserPartition(1, 'Configuration 0,1,2', 'second', [Group("0", 'Group 0'), Group("1", 'Group 1'), Group("2", 'Group 2')]).to_json()
],
},
})
def populate_course_fixture(self, course_fixture): def populate_course_fixture(self, course_fixture):
""" Populates the course """
course_fixture.add_advanced_settings( course_fixture.add_advanced_settings(
{u"advanced_modules": {"value": ["split_test"]}} {
u"advanced_modules": {"value": ["split_test"]},
u"user_partitions": {"value": [
UserPartition(0, 'Configuration alpha,beta', 'first', [Group("0", 'alpha'), Group("1", 'beta')]).to_json(),
UserPartition(1, 'Configuration 0,1,2', 'second', [Group("0", 'Group 0'), Group("1", 'Group 1'), Group("2", 'Group 2')]).to_json()
]}
}
) )
course_fixture.add_children( course_fixture.add_children(
...@@ -99,6 +91,16 @@ class SplitTest(ContainerBase, SplitTestMixin): ...@@ -99,6 +91,16 @@ class SplitTest(ContainerBase, SplitTestMixin):
) )
) )
def verify_add_missing_groups_button_not_present(self, container):
"""
Checks that the "add missing groups" button/link is not present.
"""
def missing_groups_button_not_present():
button_present = container.missing_groups_button_present()
return (not button_present, not button_present)
Promise(missing_groups_button_not_present, "Add missing groups button should not be showing.").fulfill()
def create_poorly_configured_split_instance(self): def create_poorly_configured_split_instance(self):
""" """
Creates a split test instance with a missing group and an inactive group. Creates a split test instance with a missing group and an inactive group.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment