bokchoy tests for move xblocks
This commit is contained in:
committed by
Mushtaq Ali
parent
485ffb1b68
commit
8a1ec3e690
@@ -13,10 +13,6 @@ function($, Backbone, _, gettext, HtmlUtils, StringUtils, MoveXBlockBreadcrumbVi
|
||||
var MoveXBlockBreadcrumb = Backbone.View.extend({
|
||||
el: '.breadcrumb-container',
|
||||
|
||||
defaultRenderOptions: {
|
||||
breadcrumbs: ['Course Outline']
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .parent-nav-button': 'handleBreadcrumbButtonPress'
|
||||
},
|
||||
@@ -29,7 +25,7 @@ function($, Backbone, _, gettext, HtmlUtils, StringUtils, MoveXBlockBreadcrumbVi
|
||||
render: function(options) {
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
this.template(_.extend({}, this.defaultRenderOptions, options))
|
||||
this.template(options)
|
||||
);
|
||||
Backbone.trigger('move:breadcrumbRendered');
|
||||
return this;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<%- categoryText %>:
|
||||
</span>
|
||||
</div>
|
||||
<ul class="xblock-items-container">
|
||||
<ul class="xblock-items-container" data-items-category="<%- XBlocksCategory %>">
|
||||
<% for (var i = 0; i < xblocks.length; i++) {
|
||||
var xblock = xblocks[i];
|
||||
%>
|
||||
|
||||
@@ -63,11 +63,16 @@ class ContainerPage(PageObject, HelpMixin):
|
||||
is_done = num_wrappers == (num_initialized_xblocks + num_failed_xblocks)
|
||||
return (is_done, is_done)
|
||||
|
||||
def _loading_spinner_hidden():
|
||||
""" promise function to check loading spinner state """
|
||||
is_spinner_hidden = self.q(css='div.ui-loading.is-hidden').present
|
||||
return is_spinner_hidden, is_spinner_hidden
|
||||
|
||||
# First make sure that an element with the view-container class is present on the page,
|
||||
# and then wait for the loading spinner to go away and all the xblocks to be initialized.
|
||||
return (
|
||||
self.q(css='body.view-container').present and
|
||||
self.q(css='div.ui-loading.is-hidden').present and
|
||||
Promise(_loading_spinner_hidden, 'loading spinner is hidden.').fulfill() and
|
||||
Promise(_is_finished_loading, 'Finished rendering the xblock wrappers.').fulfill()
|
||||
)
|
||||
|
||||
@@ -101,6 +106,13 @@ class ContainerPage(PageObject, HelpMixin):
|
||||
"""
|
||||
return self._get_xblocks(".is-active ")
|
||||
|
||||
@property
|
||||
def displayed_children(self):
|
||||
"""
|
||||
Return a list of displayed xblocks loaded on the container page.
|
||||
"""
|
||||
return self._get_xblocks()[0].children
|
||||
|
||||
@property
|
||||
def publish_title(self):
|
||||
"""
|
||||
@@ -262,6 +274,29 @@ class ContainerPage(PageObject, HelpMixin):
|
||||
"""
|
||||
return _click_edit(self, '.edit-button', '.xblock-studio_view')
|
||||
|
||||
def verify_confirmation_message(self, message):
|
||||
"""
|
||||
Verify for confirmation message.
|
||||
"""
|
||||
def _verify_message():
|
||||
""" promise function to check confirmation message state """
|
||||
text = self.q(css='#page-alert .alert.confirmation #alert-confirmation-title').text
|
||||
return text and message in text[0]
|
||||
|
||||
self.wait_for(_verify_message, description='confirmation message present')
|
||||
|
||||
def click_undo_move_link(self):
|
||||
"""
|
||||
Click undo move link.
|
||||
"""
|
||||
click_css(self, '#page-alert .alert.confirmation .nav-actions .action-primary')
|
||||
|
||||
def click_take_me_link(self):
|
||||
"""
|
||||
Click take me there link.
|
||||
"""
|
||||
click_css(self, '#page-alert .alert.confirmation .nav-actions .action-secondary', require_notification=False)
|
||||
|
||||
def add_missing_groups(self):
|
||||
"""
|
||||
Click the "add missing groups" link.
|
||||
@@ -382,7 +417,7 @@ class XBlockWrapper(PageObject):
|
||||
"""
|
||||
Will return any first-generation descendant xblocks of this xblock.
|
||||
"""
|
||||
descendants = self.q(css=self._bounded_selector(self.BODY_SELECTOR)).map(
|
||||
descendants = self.q(css=self._bounded_selector(self.BODY_SELECTOR)).filter(lambda el: el.is_displayed()).map(
|
||||
lambda el: XBlockWrapper(self.browser, el.get_attribute('data-locator'))).results
|
||||
|
||||
# Now remove any non-direct descendants.
|
||||
@@ -468,6 +503,13 @@ class XBlockWrapper(PageObject):
|
||||
"""
|
||||
return self.q(css=self._bounded_selector('.visibility-button')).is_present()
|
||||
|
||||
@property
|
||||
def has_move_modal_button(self):
|
||||
"""
|
||||
Returns True if this xblock has move modal button else False
|
||||
"""
|
||||
return self.q(css=self._bounded_selector('.move-button')).is_present()
|
||||
|
||||
def go_to_container(self):
|
||||
"""
|
||||
Open the container page linked to by this xblock, and return
|
||||
@@ -505,6 +547,15 @@ class XBlockWrapper(PageObject):
|
||||
"""
|
||||
self._click_button('settings_tab')
|
||||
|
||||
def open_move_modal(self):
|
||||
"""
|
||||
Opens the move modal.
|
||||
"""
|
||||
click_css(self, '.move-button', require_notification=False)
|
||||
self.wait_for(
|
||||
lambda: self.q(css='.modal-window.move-modal').visible, description='move modal is visible'
|
||||
)
|
||||
|
||||
def set_field_val(self, field_display_name, field_value):
|
||||
"""
|
||||
If editing, set the value of a field.
|
||||
|
||||
78
common/test/acceptance/pages/studio/move_xblock.py
Normal file
78
common/test/acceptance/pages/studio/move_xblock.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Move XBlock Modal Page Object
|
||||
"""
|
||||
from bok_choy.page_object import PageObject
|
||||
from common.test.acceptance.pages.common.utils import click_css
|
||||
|
||||
|
||||
class MoveModalView(PageObject):
|
||||
"""
|
||||
A base class for move xblock
|
||||
"""
|
||||
|
||||
def __init__(self, browser):
|
||||
"""
|
||||
Arguments:
|
||||
browser (selenium.webdriver): The Selenium-controlled browser that this page is loaded in.
|
||||
"""
|
||||
super(MoveModalView, self).__init__(browser)
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='.modal-window.move-modal').present
|
||||
|
||||
def url(self):
|
||||
"""
|
||||
Returns None because this is not directly accessible via URL.
|
||||
"""
|
||||
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)
|
||||
|
||||
def click_forward_button(self, source_index):
|
||||
"""
|
||||
Click forward button at specified `source_index`.
|
||||
"""
|
||||
css = '.move-modal .xblock-items-container .xblock-item'
|
||||
self.q(css='.button-forward').nth(source_index).click()
|
||||
self.wait_for(
|
||||
lambda: len(self.q(css=css).results) > 0, description='children are visible'
|
||||
)
|
||||
|
||||
def click_move_button(self):
|
||||
"""
|
||||
Click move button.
|
||||
"""
|
||||
self.q(css='.modal-actions .action-move').first.click()
|
||||
|
||||
@property
|
||||
def is_move_button_enabled(self):
|
||||
"""
|
||||
Returns True if move button on modal is enabled else False.
|
||||
"""
|
||||
return not self.q(css='.modal-actions .action-move.is-disabled').present
|
||||
|
||||
@property
|
||||
def children_category(self):
|
||||
"""
|
||||
Get displayed children category.
|
||||
"""
|
||||
return self.q(css='.xblock-items-container').attrs('data-items-category')[0]
|
||||
|
||||
def navigate_to_category(self, category, navigation_options):
|
||||
"""
|
||||
Navigates to specifec `category` for a specified `source_index`.
|
||||
"""
|
||||
child_category = self.children_category
|
||||
while child_category != category:
|
||||
self.click_forward_button(navigation_options[child_category])
|
||||
child_category = self.children_category
|
||||
@@ -10,6 +10,7 @@ from common.test.acceptance.fixtures.course import XBlockFixtureDesc
|
||||
from common.test.acceptance.pages.studio.component_editor import ComponentEditorView, ComponentVisibilityEditorView
|
||||
from common.test.acceptance.pages.studio.container import ContainerPage
|
||||
from common.test.acceptance.pages.studio.html_component_editor import HtmlComponentEditorView
|
||||
from common.test.acceptance.pages.studio.move_xblock import MoveModalView
|
||||
from common.test.acceptance.pages.studio.utils import add_discussion, drag
|
||||
from common.test.acceptance.pages.lms.courseware import CoursewarePage
|
||||
from common.test.acceptance.pages.lms.staff_view import StaffPage
|
||||
@@ -1136,3 +1137,136 @@ class ProblemCategoryTabsTest(ContainerBase):
|
||||
"Text Input with Hints and Feedback",
|
||||
]
|
||||
self.assertEqual(page.get_category_tab_components('problem', 1), expected_components)
|
||||
|
||||
|
||||
@attr(shard=1)
|
||||
class MoveComponentTest(ContainerBase):
|
||||
"""
|
||||
Tests of moving an XBlock to another XBlock.
|
||||
"""
|
||||
def setUp(self, is_staff=True):
|
||||
super(MoveComponentTest, self).setUp(is_staff=is_staff)
|
||||
self.container = ContainerPage(self.browser, None)
|
||||
self.move_modal_view = MoveModalView(self.browser)
|
||||
|
||||
self.navigation_options = {
|
||||
'section': 0,
|
||||
'subsection': 0,
|
||||
'unit': 1,
|
||||
}
|
||||
self.source_xblock_category = 'component'
|
||||
self.message_move = 'Success! "HTML 11" has been moved.'
|
||||
self.message_undo = 'Move cancelled. "HTML 11" has been moved back to its original location.'
|
||||
|
||||
def populate_course_fixture(self, course_fixture):
|
||||
"""
|
||||
Sets up a course structure.
|
||||
"""
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.unit_page1 = XBlockFixtureDesc('vertical', 'Test Unit 1').add_children(
|
||||
XBlockFixtureDesc('html', 'HTML 11'),
|
||||
XBlockFixtureDesc('html', 'HTML 12')
|
||||
)
|
||||
self.unit_page2 = XBlockFixtureDesc('vertical', 'Test Unit 2').add_children(
|
||||
XBlockFixtureDesc('html', 'HTML 21'),
|
||||
XBlockFixtureDesc('html', 'HTML 22')
|
||||
)
|
||||
course_fixture.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
self.unit_page1,
|
||||
self.unit_page2
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def verify_move_opertions(self, operation, component_display_names_after_operation):
|
||||
"""
|
||||
Verify move operations.
|
||||
|
||||
Arguments:
|
||||
operation (str), `move` or `undo move` operation
|
||||
component_display_names_after_operation (dict) display names of components after operation in source/dest
|
||||
"""
|
||||
unit_page = self.go_to_unit_page(unit_name='Test Unit 1')
|
||||
components = unit_page.displayed_children
|
||||
self.assertEqual(len(components), 2)
|
||||
|
||||
components[0].open_move_modal()
|
||||
self.move_modal_view.navigate_to_category(self.source_xblock_category, self.navigation_options)
|
||||
self.assertEqual(self.move_modal_view.is_move_button_enabled, True)
|
||||
|
||||
self.move_modal_view.click_move_button()
|
||||
self.container.verify_confirmation_message(self.message_move)
|
||||
self.assertEqual(len(unit_page.displayed_children), 1)
|
||||
|
||||
if operation == 'move':
|
||||
self.container.click_take_me_link()
|
||||
elif operation == 'undo_move':
|
||||
self.container.click_undo_move_link()
|
||||
self.container.verify_confirmation_message(self.message_undo)
|
||||
|
||||
unit_page = ContainerPage(self.browser, self.unit_page2.locator)
|
||||
components = unit_page.displayed_children
|
||||
self.assertEqual(
|
||||
[component.name for component in components],
|
||||
component_display_names_after_operation
|
||||
)
|
||||
|
||||
def test_move(self):
|
||||
"""
|
||||
Test if we can move a component successfully.
|
||||
|
||||
Given I am a staff user
|
||||
When I go to unit page in first section
|
||||
Then I open the move modal
|
||||
Then I navigate to unit in second section from within move modal
|
||||
Then I see move button is enabled
|
||||
Then I click on the move button
|
||||
Then I see move operation successfull message
|
||||
When I go to unit page in second section
|
||||
Then I see move compoenent there
|
||||
"""
|
||||
self.verify_move_opertions(
|
||||
operation='move',
|
||||
component_display_names_after_operation=['HTML 21', 'HTML 22', 'HTML 11']
|
||||
)
|
||||
|
||||
def test_undo_move(self):
|
||||
"""
|
||||
Test if we can undo move a component successfully.
|
||||
|
||||
Given I am a staff user
|
||||
When I go to unit page in first section
|
||||
Then I open the move modal
|
||||
Then I click on the move button
|
||||
Then I see move operation successfull message
|
||||
When I clicked on undo move link
|
||||
Then I verified that undo move operation is successfull
|
||||
"""
|
||||
self.verify_move_opertions(
|
||||
operation='undo_move',
|
||||
component_display_names_after_operation=['HTML 11', 'HTML 12']
|
||||
)
|
||||
|
||||
def test_a11y(self):
|
||||
"""
|
||||
Verify move modal a11y.
|
||||
"""
|
||||
unit_page = self.go_to_unit_page(unit_name='Test Unit 1')
|
||||
|
||||
unit_page.a11y_audit.config.set_scope(
|
||||
include=[".modal-window.move-modal"]
|
||||
)
|
||||
unit_page.a11y_audit.config.set_rules({
|
||||
'ignore': [
|
||||
'color-contrast',
|
||||
'link-href',
|
||||
]
|
||||
})
|
||||
|
||||
unit_page.displayed_children[0].open_move_modal()
|
||||
|
||||
for category in ['section', 'subsection', 'component']:
|
||||
self.move_modal_view.navigate_to_category(category, self.navigation_options)
|
||||
unit_page.a11y_audit.check_for_accessibility_errors()
|
||||
|
||||
Reference in New Issue
Block a user