Commit 2cdd005f by chrisndodge

Merge pull request #1037 from edx/rc/2013-09-18

Rc/2013 09 18
parents d3dc9d27 71a5df72
......@@ -5,6 +5,10 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
Studio/LMS: Added ability to set due date formatting through Studio's Advanced Settings.
The key is due_date_display_format, and the value should be a format supported by Python's
strftime function.
Common: Added configurable backends for tracking events. Tracking events using
the python logging module is the default backend. Support for MongoDB and a
Django database is also available.
......
......@@ -67,7 +67,7 @@ def get_index(name):
page_name_css = 'section[data-type="HTMLModule"]'
all_pages = world.css_find(page_name_css)
for i in range(len(all_pages)):
if all_pages[i].html == '\n {name}\n'.format(name=name):
if world.retry_on_exception(lambda: all_pages[i].html) == '\n {name}\n'.format(name=name):
return i
return None
......
......@@ -6,6 +6,7 @@ import time
import platform
from urllib import quote_plus
from selenium.common.exceptions import WebDriverException, TimeoutException
from selenium.common.exceptions import StaleElementReferenceException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
......@@ -45,18 +46,25 @@ def css_has_text(css_selector, text, index=0):
@world.absorb
def wait_for(func, timeout=5):
WebDriverWait(world.browser.driver, timeout).until(func)
WebDriverWait(
driver=world.browser.driver,
timeout=timeout,
ignored_exceptions=(StaleElementReferenceException)
).until(func)
def wait_for_present(css_selector, timeout=30):
"""
Waiting for the element to be present in the DOM.
Throws an error if the wait_for time expires.
Throws an error if the WebDriverWait timeout clock expires.
Otherwise this method will return None
"""
try:
WebDriverWait(driver=world.browser.driver,
timeout=60).until(EC.presence_of_element_located((By.CSS_SELECTOR, css_selector,)))
WebDriverWait(
driver=world.browser.driver,
timeout=timeout,
ignored_exceptions=(StaleElementReferenceException)
).until(EC.presence_of_element_located((By.CSS_SELECTOR, css_selector,)))
except TimeoutException:
raise TimeoutException("Timed out waiting for {} to be present.".format(css_selector))
......@@ -65,12 +73,15 @@ def wait_for_present(css_selector, timeout=30):
def wait_for_visible(css_selector, timeout=30):
"""
Waiting for the element to be visible in the DOM.
Throws an error if the wait_for time expires.
Throws an error if the WebDriverWait timeout clock expires.
Otherwise this method will return None
"""
try:
WebDriverWait(driver=world.browser.driver,
timeout=timeout).until(EC.visibility_of_element_located((By.CSS_SELECTOR, css_selector,)))
WebDriverWait(
driver=world.browser.driver,
timeout=timeout,
ignored_exceptions=(StaleElementReferenceException)
).until(EC.visibility_of_element_located((By.CSS_SELECTOR, css_selector,)))
except TimeoutException:
raise TimeoutException("Timed out waiting for {} to be visible.".format(css_selector))
......@@ -79,12 +90,15 @@ def wait_for_visible(css_selector, timeout=30):
def wait_for_invisible(css_selector, timeout=30):
"""
Waiting for the element to be either invisible or not present on the DOM.
Throws an error if the wait_for time expires.
Throws an error if the WebDriverWait timeout clock expires.
Otherwise this method will return None
"""
try:
WebDriverWait(driver=world.browser.driver,
timeout=timeout).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, css_selector,)))
WebDriverWait(
driver=world.browser.driver,
timeout=timeout,
ignored_exceptions=(StaleElementReferenceException)
).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, css_selector,)))
except TimeoutException:
raise TimeoutException("Timed out waiting for {} to be invisible.".format(css_selector))
......@@ -93,14 +107,17 @@ def wait_for_invisible(css_selector, timeout=30):
def wait_for_clickable(css_selector, timeout=30):
"""
Waiting for the element to be present and clickable.
Throws an error if the wait_for time expires.
Throws an error if the WebDriverWait timeout clock expires.
Otherwise this method will return None.
"""
# Sometimes the element is clickable then gets obscured.
# In this case, pause so that it is not reported clickable too early
try:
WebDriverWait(world.browser.driver,
timeout=timeout).until(EC.element_to_be_clickable((By.CSS_SELECTOR, css_selector,)))
WebDriverWait(
driver=world.browser.driver,
timeout=timeout,
ignored_exceptions=(StaleElementReferenceException)
).until(EC.element_to_be_clickable((By.CSS_SELECTOR, css_selector,)))
except TimeoutException:
raise TimeoutException("Timed out waiting for {} to be clickable.".format(css_selector))
......@@ -133,7 +150,7 @@ def css_click(css_selector, index=0, wait_time=30):
# another element might be on top of it. In this case, try
# clicking in the upper left corner.
try:
return world.css_find(css_selector)[index].click()
return retry_on_exception(lambda: world.css_find(css_selector)[index].click())
except WebDriverException:
return css_click_at(css_selector, index=index)
......@@ -177,19 +194,19 @@ def id_click(elem_id):
@world.absorb
def css_fill(css_selector, text, index=0):
css_find(css_selector)[index].fill(text)
retry_on_exception(lambda: css_find(css_selector)[index].fill(text))
@world.absorb
def click_link(partial_text, index=0):
world.browser.find_link_by_partial_text(partial_text)[index].click()
retry_on_exception(lambda: world.browser.find_link_by_partial_text(partial_text)[index].click())
@world.absorb
def css_text(css_selector, index=0, timeout=30):
# Wait for the css selector to appear
if is_css_present(css_selector):
return css_find(css_selector, wait_time=timeout)[index].text
return retry_on_exception(lambda: css_find(css_selector, wait_time=timeout)[index].text)
else:
return ""
......@@ -198,7 +215,7 @@ def css_text(css_selector, index=0, timeout=30):
def css_value(css_selector, index=0):
# Wait for the css selector to appear
if is_css_present(css_selector):
return css_find(css_selector)[index].value
return retry_on_exception(lambda: css_find(css_selector)[index].value)
else:
return ""
......@@ -209,18 +226,18 @@ def css_html(css_selector, index=0):
Returns the HTML of a css_selector
"""
assert is_css_present(css_selector)
return css_find(css_selector)[index].html
return retry_on_exception(lambda: css_find(css_selector)[index].html)
@world.absorb
def css_has_class(css_selector, class_name, index=0):
return css_find(css_selector)[index].has_class(class_name)
return retry_on_exception(lambda: css_find(css_selector)[index].has_class(class_name))
@world.absorb
def css_visible(css_selector, index=0):
assert is_css_present(css_selector)
return css_find(css_selector)[index].visible
return retry_on_exception(lambda: css_find(css_selector)[index].visible)
@world.absorb
......@@ -277,15 +294,21 @@ def trigger_event(css_selector, event='change', index=0):
@world.absorb
def retry_on_exception(func, max_attempts=5):
def retry_on_exception(func, max_attempts=5, ignored_exceptions=StaleElementReferenceException):
"""
Retry the interaction, ignoring the passed exceptions.
By default ignore StaleElementReferenceException, which happens often in our application
when the DOM is being manipulated by client side JS.
Note that ignored_exceptions is passed directly to the except block, and as such can be
either a single exception or multiple exceptions as a parenthesized tuple.
"""
attempt = 0
while attempt < max_attempts:
try:
return func()
break
except WebDriverException:
except ignored_exceptions:
world.wait(1)
attempt += 1
except:
attempt += 1
assert_true(attempt < max_attempts, 'Ran out of attempts to execute {}'.format(func))
......@@ -227,17 +227,13 @@ class LTIModule(LTIFields, XModule):
body=body,
headers=headers)
except ValueError: # scheme not in url
# Stubbing headers for now:
#https://github.com/idan/oauthlib/blob/master/oauthlib/oauth1/rfc5849/signature.py#L136
#Stubbing headers for now:
headers = {
u'Content-Type': u'application/x-www-form-urlencoded',
u'Authorization': u'oAuth ' # cont..
u'oauth_nonce="80966668944732164491378916897", ' # cont..
u'oauth_timestamp="1378916897", ' # cont..
u'oauth_version="1.0", ' # cont..
u'oauth_signature_method="HMAC-SHA1", ' # cont..
u'oauth_consumer_key="", ' # cont..
u'oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"',
}
u'Authorization': u'OAuth oauth_nonce="80966668944732164491378916897", \
oauth_timestamp="1378916897", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", \
oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
params = headers['Authorization']
# parse headers to pass to template as part of context:
......
......@@ -1661,13 +1661,13 @@
margin: 0 flex-gutter() 0 0;
.title {
@extend .hd-lv4;
@extend %hd-lv4;
margin-bottom: ($baseline/4);
}
.copy {
@extend .t-copy-sub1;
@extend .t-weight3;
@extend %t-copy-sub1;
@extend %t-weight3;
}
.list-actions {
......@@ -1675,7 +1675,7 @@
}
.action-verify label {
@extend .t-copy-sub1;
@extend %t-copy-sub1;
}
}
......
......@@ -4,13 +4,13 @@
<div class="home">
<a href="#" class="home-icon">
<i class="icon icon-home"></i>
<span class="text-sr">${_("Discussion Home")}</span>
<span class="sr">${_("Discussion Home")}</span>
</a>
</div>
<div class="browse is-open">
<a href="#" class="browse-topic-drop-icon">
<i class="icon icon-reorder"></i>
<span class="text-sr">${_("Discussion Topics")}</span>
<span class="sr">${_("Discussion Topics")}</span>
</a>
<a href="#" class="browse-topic-drop-btn"><span class="current-board">${_("Show All Discussions")}</span> <span class="drop-arrow">▾</span></a>
</div>
......
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