This commit implements STUD-1490, allowing creation of components on the container page. It also enables the delete and duplicate buttons now that new content can be created that would benefit. Note that it also creates shared functionality for adding components, and refactors the unit page to use it too.
306 lines
13 KiB
Python
306 lines
13 KiB
Python
"""
|
|
Acceptance tests for Studio related to the container page.
|
|
"""
|
|
from ..pages.studio.auto_auth import AutoAuthPage
|
|
from ..pages.studio.overview import CourseOutlinePage
|
|
from ..fixtures.course import CourseFixture, XBlockFixtureDesc
|
|
|
|
from .helpers import UniqueCourseTest
|
|
|
|
|
|
class ContainerBase(UniqueCourseTest):
|
|
"""
|
|
Base class for tests that do operations on the container page.
|
|
"""
|
|
__test__ = False
|
|
|
|
def setUp(self):
|
|
"""
|
|
Create a unique identifier for the course used in this test.
|
|
"""
|
|
# Ensure that the superclass sets up
|
|
super(ContainerBase, self).setUp()
|
|
|
|
self.auth_page = AutoAuthPage(self.browser, staff=True)
|
|
self.outline = CourseOutlinePage(
|
|
self.browser,
|
|
self.course_info['org'],
|
|
self.course_info['number'],
|
|
self.course_info['run']
|
|
)
|
|
|
|
self.container_title = ""
|
|
self.group_a = "Expand or Collapse\nGroup A"
|
|
self.group_b = "Expand or Collapse\nGroup B"
|
|
self.group_empty = "Expand or Collapse\nGroup Empty"
|
|
self.group_a_item_1 = "Group A Item 1"
|
|
self.group_a_item_2 = "Group A Item 2"
|
|
self.group_b_item_1 = "Group B Item 1"
|
|
self.group_b_item_2 = "Group B Item 2"
|
|
|
|
self.group_a_handle = 0
|
|
self.group_a_item_1_handle = 1
|
|
self.group_a_item_2_handle = 2
|
|
self.group_empty_handle = 3
|
|
self.group_b_handle = 4
|
|
self.group_b_item_1_handle = 5
|
|
self.group_b_item_2_handle = 6
|
|
|
|
self.group_a_item_1_action_index = 0
|
|
self.group_a_item_2_action_index = 1
|
|
|
|
self.duplicate_label = "Duplicate of '{0}'"
|
|
self.discussion_label = "Discussion"
|
|
|
|
self.setup_fixtures()
|
|
|
|
self.auth_page.visit()
|
|
|
|
def setup_fixtures(self):
|
|
course_fix = CourseFixture(
|
|
self.course_info['org'],
|
|
self.course_info['number'],
|
|
self.course_info['run'],
|
|
self.course_info['display_name']
|
|
)
|
|
|
|
course_fix.add_children(
|
|
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
|
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
|
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
|
XBlockFixtureDesc('vertical', 'Test Container').add_children(
|
|
XBlockFixtureDesc('vertical', 'Group A').add_children(
|
|
XBlockFixtureDesc('html', self.group_a_item_1),
|
|
XBlockFixtureDesc('html', self.group_a_item_2)
|
|
),
|
|
XBlockFixtureDesc('vertical', 'Group Empty'),
|
|
XBlockFixtureDesc('vertical', 'Group B').add_children(
|
|
XBlockFixtureDesc('html', self.group_b_item_1),
|
|
XBlockFixtureDesc('html', self.group_b_item_2)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
).install()
|
|
|
|
def go_to_container_page(self, make_draft=False):
|
|
self.outline.visit()
|
|
subsection = self.outline.section('Test Section').subsection('Test Subsection')
|
|
unit = subsection.toggle_expand().unit('Test Unit').go_to()
|
|
if make_draft:
|
|
unit.edit_draft()
|
|
container = unit.components[0].go_to_container()
|
|
return container
|
|
|
|
def verify_ordering(self, container, expected_orderings):
|
|
xblocks = container.xblocks
|
|
for expected_ordering in expected_orderings:
|
|
for xblock in xblocks:
|
|
parent = expected_ordering.keys()[0]
|
|
if xblock.name == parent:
|
|
children = xblock.children
|
|
expected_length = len(expected_ordering.get(parent))
|
|
self.assertEqual(
|
|
expected_length, len(children),
|
|
"Number of children incorrect for group {0}. Expected {1} but got {2}.".format(parent, expected_length, len(children)))
|
|
for idx, expected in enumerate(expected_ordering.get(parent)):
|
|
self.assertEqual(expected, children[idx].name)
|
|
break
|
|
|
|
def do_action_and_verify(self, action, expected_ordering):
|
|
container = self.go_to_container_page(make_draft=True)
|
|
action(container)
|
|
|
|
self.verify_ordering(container, expected_ordering)
|
|
|
|
# Reload the page to see that the change was persisted.
|
|
container = self.go_to_container_page()
|
|
self.verify_ordering(container, expected_ordering)
|
|
|
|
|
|
class DragAndDropTest(ContainerBase):
|
|
"""
|
|
Tests of reordering within the container page.
|
|
"""
|
|
__test__ = True
|
|
|
|
def drag_and_verify(self, source, target, expected_ordering):
|
|
self.do_action_and_verify(
|
|
lambda (container): container.drag(source, target),
|
|
expected_ordering
|
|
)
|
|
|
|
def test_reorder_in_group(self):
|
|
"""
|
|
Drag Group A Item 2 before Group A Item 1.
|
|
"""
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_2, self.group_a_item_1]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.drag_and_verify(self.group_a_item_2_handle, self.group_a_item_1_handle, expected_ordering)
|
|
|
|
def test_drag_to_top(self):
|
|
"""
|
|
Drag Group A Item 1 to top level (outside of Group A).
|
|
"""
|
|
expected_ordering = [{self.container_title: [self.group_a_item_1, self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.drag_and_verify(self.group_a_item_1_handle, self.group_a_handle, expected_ordering)
|
|
|
|
def test_drag_into_different_group(self):
|
|
"""
|
|
Drag Group B Item 1 into Group A (first element).
|
|
"""
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_b_item_1, self.group_a_item_1, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.drag_and_verify(self.group_b_item_1_handle, self.group_a_item_1_handle, expected_ordering)
|
|
|
|
def test_drag_group_into_group(self):
|
|
"""
|
|
Drag Group B into Group A (first element).
|
|
"""
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty]},
|
|
{self.group_a: [self.group_b, self.group_a_item_1, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.drag_and_verify(self.group_b_handle, self.group_a_item_1_handle, expected_ordering)
|
|
|
|
def test_drag_after_addition(self):
|
|
"""
|
|
Add some components and then verify that drag and drop still works.
|
|
"""
|
|
group_a_menu = 0
|
|
|
|
def add_new_components_and_rearrange(container):
|
|
# Add a video component to Group 1
|
|
container.add_discussion(group_a_menu)
|
|
# Duplicate the first item in Group A
|
|
container.duplicate(self.group_a_item_1_action_index)
|
|
|
|
first_handle = self.group_a_item_1_handle
|
|
# Drag newly added video component to top.
|
|
container.drag(first_handle + 3, first_handle)
|
|
# Drag duplicated component to top.
|
|
container.drag(first_handle + 2, first_handle)
|
|
|
|
duplicate_label = self.duplicate_label.format(self.group_a_item_1)
|
|
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [duplicate_label, self.discussion_label, self.group_a_item_1, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
|
|
self.do_action_and_verify(add_new_components_and_rearrange, expected_ordering)
|
|
|
|
|
|
class AddComponentTest(ContainerBase):
|
|
"""
|
|
Tests of adding a component to the container page.
|
|
"""
|
|
__test__ = True
|
|
|
|
def add_and_verify(self, menu_index, expected_ordering):
|
|
self.do_action_and_verify(
|
|
lambda (container): container.add_discussion(menu_index),
|
|
expected_ordering
|
|
)
|
|
|
|
def test_add_component_in_group(self):
|
|
group_b_menu = 2
|
|
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_1, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2, self.discussion_label]},
|
|
{self.group_empty: []}]
|
|
self.add_and_verify(group_b_menu, expected_ordering)
|
|
|
|
def test_add_component_in_empty_group(self):
|
|
group_empty_menu = 1
|
|
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_1, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: [self.discussion_label]}]
|
|
self.add_and_verify(group_empty_menu, expected_ordering)
|
|
|
|
def test_add_component_in_container(self):
|
|
container_menu = 3
|
|
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b, self.discussion_label]},
|
|
{self.group_a: [self.group_a_item_1, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.add_and_verify(container_menu, expected_ordering)
|
|
|
|
|
|
class DuplicateComponentTest(ContainerBase):
|
|
"""
|
|
Tests of duplicating a component on the container page.
|
|
"""
|
|
__test__ = True
|
|
|
|
def duplicate_and_verify(self, source_index, expected_ordering):
|
|
self.do_action_and_verify(
|
|
lambda (container): container.duplicate(source_index),
|
|
expected_ordering
|
|
)
|
|
|
|
def test_duplicate_first_in_group(self):
|
|
duplicate_label = self.duplicate_label.format(self.group_a_item_1)
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_1, duplicate_label, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.duplicate_and_verify(self.group_a_item_1_action_index, expected_ordering)
|
|
|
|
def test_duplicate_second_in_group(self):
|
|
duplicate_label = self.duplicate_label.format(self.group_a_item_2)
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_1, self.group_a_item_2, duplicate_label]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.duplicate_and_verify(self.group_a_item_2_action_index, expected_ordering)
|
|
|
|
def test_duplicate_the_duplicate(self):
|
|
first_duplicate_label = self.duplicate_label.format(self.group_a_item_1)
|
|
second_duplicate_label = self.duplicate_label.format(first_duplicate_label)
|
|
|
|
expected_ordering = [
|
|
{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_1, first_duplicate_label, second_duplicate_label, self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}
|
|
]
|
|
|
|
def duplicate_twice(container):
|
|
container.duplicate(self.group_a_item_1_action_index)
|
|
container.duplicate(self.group_a_item_1_action_index + 1)
|
|
|
|
self.do_action_and_verify(duplicate_twice, expected_ordering)
|
|
|
|
|
|
class DeleteComponentTest(ContainerBase):
|
|
"""
|
|
Tests of deleting a component from the container page.
|
|
"""
|
|
__test__ = True
|
|
|
|
def delete_and_verify(self, source_index, expected_ordering):
|
|
self.do_action_and_verify(
|
|
lambda (container): container.delete(source_index),
|
|
expected_ordering
|
|
)
|
|
|
|
def test_delete_first_in_group(self):
|
|
expected_ordering = [{self.container_title: [self.group_a, self.group_empty, self.group_b]},
|
|
{self.group_a: [self.group_a_item_2]},
|
|
{self.group_b: [self.group_b_item_1, self.group_b_item_2]},
|
|
{self.group_empty: []}]
|
|
self.delete_and_verify(self.group_a_item_1_action_index, expected_ordering)
|