Commit c21dbe4c by Jay Zoldak

Improvements to clicking and synchronization in Studio bok-choy tests.

parent 4bd3093e
...@@ -103,10 +103,21 @@ class ContainerPage(PageObject): ...@@ -103,10 +103,21 @@ class ContainerPage(PageObject):
def delete(self, source_index): def delete(self, source_index):
""" """
Delete the item with index source_index (based on vertical placement in page). Delete the item with index source_index (based on vertical placement in page).
Only visible items are counted in the source_index.
The index of the first item is 0.
""" """
# 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, 'a.button.action-primary', 0) click_css(self, confirmation_button_css, 0)
def edit(self): def edit(self):
""" """
...@@ -125,6 +136,7 @@ class ContainerPage(PageObject): ...@@ -125,6 +136,7 @@ class ContainerPage(PageObject):
def add_missing_groups(self): def add_missing_groups(self):
""" """
Click the "add missing groups" link. Click the "add missing groups" link.
Note that this does an ajax call.
""" """
self.q(css='.add-missing-groups-button').first.click() self.q(css='.add-missing-groups-button').first.click()
......
""" """
Utility methods useful for Studio page tests. Utility methods useful for Studio page tests.
""" """
from bok_choy.promise import Promise from bok_choy.promise import EmptyPromise
from selenium.webdriver.common.action_chains import ActionChains
def click_css(page, css, source_index=0, require_notification=True): def click_css(page, css, source_index=0, require_notification=True):
""" """
Click the button/link with the given css and index on the specified page (subclass of PageObject). Click the button/link with the given css and index on the specified page (subclass of PageObject).
Will only consider buttons with a non-zero size. Will only consider elements that are displayed and have a height and width greater than zero.
If require_notification is False (default value is True), the method will return immediately. If require_notification is False (default value is True), the method will return immediately.
Otherwise, it will wait for the "mini-notification" to appear and disappear. Otherwise, it will wait for the "mini-notification" to appear and disappear.
""" """
buttons = page.q(css=css).filter(lambda el: el.size['width'] > 0) def _is_visible(el):
target = buttons[source_index] # Only make the call to size once (instead of once for the height and once for the width)
ActionChains(page.browser).click(target).release().perform() # because otherwise you will trigger a extra query on a remote element.
return el.is_displayed() and all(size > 0 for size in el.size.itervalues())
# Disable jQuery animations for faster testing with more reliable synchronization
page.browser.execute_script("jQuery.fx.off = true;")
# Click on the element in the browser
page.q(css=css).filter(lambda el: _is_visible(el)).nth(source_index).click()
# Some buttons trigger ajax posts
# (e.g. .add-missing-groups-button as configured in split_test_author_view.js)
# so after you click anything wait for the ajax call to finish
page.wait_for_ajax()
if require_notification: if require_notification:
wait_for_notification(page) wait_for_notification(page)
...@@ -26,15 +38,13 @@ def wait_for_notification(page): ...@@ -26,15 +38,13 @@ def wait_for_notification(page):
Waits for the "mini-notification" to appear and disappear on the given page (subclass of PageObject). Waits for the "mini-notification" to appear and disappear on the given page (subclass of PageObject).
""" """
def _is_saving(): def _is_saving():
num_notifications = page.q(css='.wrapper-notification-mini.is-shown').present return page.q(css='.wrapper-notification-mini.is-shown').present
return (num_notifications == 1, num_notifications)
def _is_saving_done(): def _is_saving_done():
num_notifications = page.q(css='.wrapper-notification-mini.is-hiding').present return page.q(css='.wrapper-notification-mini.is-hiding').present
return (num_notifications == 1, num_notifications)
Promise(_is_saving, 'Notification should have been shown.', timeout=60).fulfill() EmptyPromise(_is_saving, 'Notification should have been shown.', timeout=60).fulfill()
Promise(_is_saving_done, 'Notification should have been hidden.', timeout=60).fulfill() EmptyPromise(_is_saving_done, 'Notification should have been hidden.', timeout=60).fulfill()
def press_the_notification_button(page, name): def press_the_notification_button(page, name):
...@@ -66,18 +76,24 @@ def add_advanced_component(page, menu_index, name): ...@@ -66,18 +76,24 @@ def add_advanced_component(page, menu_index, name):
menu_index specifies which instance of the menus should be used (based on vertical menu_index specifies which instance of the menus should be used (based on vertical
placement within the page). placement within the page).
""" """
# Click on the Advanced icon.
click_css(page, 'a>span.large-advanced-icon', menu_index, require_notification=False) click_css(page, 'a>span.large-advanced-icon', menu_index, require_notification=False)
# Sporadically, the advanced component was not getting created after the click_css call on the category (below). # This does an animation to hide the first level of buttons
# Try making sure that the menu of advanced components is visible before clicking (the HTML is always on the # and instead show the Advanced buttons that are available.
# We should be OK though because click_css turns off jQuery animations
# Make sure that the menu of advanced components is visible before clicking (the HTML is always on the
# page, but will have display none until the large-advanced-icon is clicked). # page, but will have display none until the large-advanced-icon is clicked).
def is_advanced_components_showing(): page.wait_for_element_visibility('.new-component-advanced', 'Advanced component menu is visible')
advanced_buttons = page.q(css=".new-component-advanced").filter(lambda el: el.size['width'] > 0)
return (len(advanced_buttons) == 1, len(advanced_buttons))
Promise(is_advanced_components_showing, "Advanced component menu not showing").fulfill() # Now click on the component to add it.
component_css = 'a[data-category={}]'.format(name)
page.wait_for_element_visibility(component_css, 'Advanced component {} is visible'.format(name))
click_css(page, 'a[data-category={}]'.format(name)) # Adding some components, e.g. the Discussion component, will make an ajax call
# but we should be OK because the click_css method is written to handle that.
click_css(page, component_css, 0)
def type_in_codemirror(page, index, text, find_prefix="$"): def type_in_codemirror(page, index, text, find_prefix="$"):
......
...@@ -169,6 +169,9 @@ class SplitTest(ContainerBase, SplitTestMixin): ...@@ -169,6 +169,9 @@ class SplitTest(ContainerBase, SplitTestMixin):
Test deleting an inactive group. Test deleting an inactive group.
""" """
container = self.create_poorly_configured_split_instance() container = self.create_poorly_configured_split_instance()
# The inactive group is the 2nd group, but it is the first one
# with a visible delete button, so use index 0
container.delete(0) container.delete(0)
self.verify_groups(container, ['alpha'], [], verify_missing_groups_not_present=False) self.verify_groups(container, ['alpha'], [], verify_missing_groups_not_present=False)
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
-e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle -e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle
-e git+https://github.com/edx/event-tracking.git@0.1.0#egg=event-tracking -e git+https://github.com/edx/event-tracking.git@0.1.0#egg=event-tracking
-e git+https://github.com/edx/edx-analytics-api-client.git@0.1.0#egg=analytics-client -e git+https://github.com/edx/edx-analytics-api-client.git@0.1.0#egg=analytics-client
-e git+https://github.com/edx/bok-choy.git@82b4e82d79b9d4c6d087ebbfa26ea23235728e62#egg=bok_choy -e git+https://github.com/edx/bok-choy.git@821d3b0ac742c204a93d802a8732be024a0bce22#egg=bok_choy
-e git+https://github.com/edx-solutions/django-splash.git@9965a53c269666a30bb4e2b3f6037c138aef2a55#egg=django-splash -e git+https://github.com/edx-solutions/django-splash.git@9965a53c269666a30bb4e2b3f6037c138aef2a55#egg=django-splash
-e git+https://github.com/edx/acid-block.git@459aff7b63db8f2c5decd1755706c1a64fb4ebb1#egg=acid-xblock -e git+https://github.com/edx/acid-block.git@459aff7b63db8f2c5decd1755706c1a64fb4ebb1#egg=acid-xblock
-e git+https://github.com/edx/edx-ora2.git@release-2014-07-21T12.20#egg=edx-ora2 -e git+https://github.com/edx/edx-ora2.git@release-2014-07-21T12.20#egg=edx-ora2
......
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