Commit ef636fe9 by Braden MacDonald

Fix flaky tests

parent 7b5bc7d5
......@@ -18,7 +18,7 @@ if __name__ == "__main__":
sys.path.append(xblock_sdk_dir)
# Use the workbench settings file:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "workbench.settings")
# Configure a range of ports in case the default port of 8081 is in use
os.environ.setdefault("DJANGO_LIVE_TEST_SERVER_ADDRESS", "localhost:8081-8099")
......
......@@ -3,6 +3,7 @@
from xml.sax.saxutils import escape
from selenium.webdriver.support.ui import WebDriverWait
from bok_choy.promise import EmptyPromise
from workbench import scenarios
from xblockutils.resources import ResourceLoader
......@@ -122,3 +123,14 @@ class BaseIntegrationTest(SeleniumBaseTest):
wait = WebDriverWait(elem, 2)
wait.until(lambda e: class_name in e.get_attribute('class').split(),
u"Class name {} not in {}".format(class_name, elem.get_attribute('class')))
def wait_for_ajax(self, timeout=15):
"""
Wait for jQuery to be loaded and for all ajax requests to finish.
Same as bok-choy's PageObject.wait_for_ajax()
"""
def is_ajax_finished():
""" Check if all the ajax calls on the current page have completed. """
return self.browser.execute_script("return typeof(jQuery)!='undefined' && jQuery.active==0")
EmptyPromise(is_ajax_finished, "Finished waiting for ajax requests.", timeout=timeout).fulfill()
......@@ -3,7 +3,7 @@
from ddt import ddt, data, unpack
from mock import Mock, patch
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
......@@ -135,6 +135,7 @@ class InteractionTestBase(object):
self.drag_item_to_zone(item_value, zone_id)
else:
self.move_item_to_zone(item_value, zone_id, action_key)
self.wait_for_ajax()
def drag_item_to_zone(self, item_value, zone_id):
"""
......@@ -154,11 +155,11 @@ class InteractionTestBase(object):
Place item to descired zone using keybard interaction.
zone_id=None means place item back into the item bank.
"""
# Focus on the item:
# Focus on the item, then press the action key:
item = self._get_item_by_value(item_value)
ActionChains(self.browser).move_to_element(item).perform()
# Press the action key:
item.send_keys(action_key) # Focus is on first *zone* now
item.send_keys("")
item.send_keys(action_key)
# Focus is on first *zone* now
self.assert_grabbed_item(item)
# Get desired zone and figure out how many times we have to press Tab to focus the zone.
if zone_id is None: # moving back to the bank
......@@ -173,7 +174,7 @@ class InteractionTestBase(object):
# position of the zone (zero presses for first zone, one press for second zone, etc).
tab_press_count = self._get_zone_position(zone_id)
for _ in range(tab_press_count):
self._page.send_keys(Keys.TAB)
ActionChains(self.browser).send_keys(Keys.TAB).perform()
zone.send_keys(action_key)
def assert_grabbed_item(self, item):
......@@ -324,10 +325,8 @@ class InteractionTestBase(object):
# When using the keyboard, ensure that dropped items cannot get "grabbed".
# Assert item has no tabindex.
self.assertIsNone(item.get_attribute('tabindex'))
# Focus on the item:
ActionChains(self.browser).move_to_element(item).perform()
# Press the action key:
item.send_keys(action_key)
# Focus on the item, then press the action key:
ActionChains(self.browser).move_to_element(item).send_keys(action_key).perform()
# Assert item is not grabbed.
self.assertEqual(item.get_attribute('aria-grabbed'), 'false')
else:
......@@ -417,7 +416,7 @@ class InteractionTestBase(object):
self.assertTrue(dialog_modal_overlay.is_displayed())
self.assertTrue(dialog_modal.is_displayed())
self._page.send_keys(Keys.ESCAPE)
ActionChains(self.browser).send_keys(Keys.ESCAPE).perform()
self.assertFalse(dialog_modal_overlay.is_displayed())
self.assertFalse(dialog_modal.is_displayed())
......@@ -497,6 +496,7 @@ class AssessmentTestMixin(object):
self._wait_until_enabled(submit_button)
submit_button.click()
self.wait_for_ajax()
@ddt
......@@ -693,6 +693,7 @@ class MultipleValidOptionsInteractionTest(DefaultDataTestMixin, InteractionTestB
self.assertEqual(popup.get_attribute('class'), 'popup')
self.assert_placed_item(item.item_id, item.zone_title[i])
reset.click()
self.wait_until_disabled(reset)
def _get_scenario_xml(self):
return self._get_custom_scenario_xml("data/test_multiple_options_data.json")
......@@ -773,11 +774,18 @@ class PreventSpaceBarScrollTest(DefaultDataTestMixin, InteractionTestBase, BaseI
def get_scroll(self):
return self.browser.execute_script('return $(window).scrollTop()')
def hit_spacebar(self):
""" Send a spacebar event to the page/browser """
try:
self._page.send_keys(Keys.SPACE) # Firefox (chrome doesn't allow sending keys to non-focusable elements)
except WebDriverException:
ActionChains(self.browser).send_keys(Keys.SPACE).perform() # Chrome (Firefox types this into the URL bar)
def test_space_bar_scroll(self):
# Window should not be scrolled at first.
self.assertEqual(self.get_scroll(), 0)
# Pressing space bar while no zone is focused should scroll the window down (default browser action).
self._page.send_keys(Keys.SPACE)
self.hit_spacebar()
# Window should be scrolled down a bit.
wait = WebDriverWait(self, 2)
# While the XHR is in progress, a spinner icon is shown inside the item.
......@@ -984,3 +992,4 @@ class ZoneAlignInteractionTest(InteractionTestBase, BaseIntegrationTest):
self.scroll_down(pixels=200)
reset.click()
self.scroll_down(pixels=0)
self.wait_until_disabled(reset)
......@@ -111,9 +111,10 @@ class SizingTests(InteractionTestBase, BaseIntegrationTest):
self._check_sizes(1, self.EXPECTATIONS, expected_img_width=500)
def _size_for_mobile(self):
self.browser.set_window_size(375, 627) # iPhone 6 viewport size
width, height = 400, 627 # iPhone 6 viewport size is 375x627; this is the closest Chrome can get
self.browser.set_window_size(width, height)
wait = WebDriverWait(self.browser, 2)
wait.until(lambda browser: browser.get_window_size()["width"] == 375)
wait.until(lambda browser: browser.get_window_size()["width"] == width)
# Fix platform inconsistencies caused by scrollbar size:
self.browser.execute_script('$("body").css("margin-right", "40px")')
scrollbar_width = self.browser.execute_script(
......@@ -188,16 +189,20 @@ class SizingTests(InteractionTestBase, BaseIntegrationTest):
item_bank = self._page.find_element_by_css_selector('.item-bank')
item_bank_width = item_bank.size["width"]
item_bank_height = item_bank.size["height"]
page_width = self._page.size["width"] # self._page is the .xblock--drag-and-drop div
if is_desktop:
# If using a desktop-sized window, we can know the exact dimensions of various containers:
self.assertEqual(self._page.size["width"], 770) # self._page is the .xblock--drag-and-drop div
self.assertEqual(target_img_width, expected_img_width or 755)
self.assertEqual(item_bank_width, 755)
self.assertEqual(page_width, 770) # div has max-width: 770px
else:
self.assertEqual(self._page.size["width"], 335) # self._page is the .xblock--drag-and-drop div
self.assertEqual(target_img_width, expected_img_width or 328)
self.assertEqual(item_bank_width, 328)
window_width = self.browser.get_window_size()["width"]
self.assertLessEqual(window_width, 400)
self.assertEqual(page_width, window_width - 40)
# The item bank and other elements are inside a wrapper with 'padding: 1%', so we expect
# their width to be 98% of item_bank_width in general
self.assertAlmostEqual(target_img_width, expected_img_width or (page_width * 0.98), delta=1)
self.assertAlmostEqual(item_bank_width, page_width * 0.98, delta=1)
# Test each element, before it is placed (while it is in the item bank).
for expect in expectations:
......
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