Refactor wait_for methods in ui_helpers for acceptance tests.
This commit is contained in:
@@ -283,24 +283,33 @@ def button_disabled(step, value):
|
||||
assert world.css_has_class(button_css, 'is-disabled')
|
||||
|
||||
|
||||
def _do_studio_prompt_action(intent, action):
|
||||
"""
|
||||
Wait for a studio prompt to appear and press the specified action button
|
||||
See cms/static/js/views/feedback_prompt.js for implementation
|
||||
"""
|
||||
assert intent in ['warning', 'error', 'confirmation', 'announcement',
|
||||
'step-required', 'help', 'mini']
|
||||
assert action in ['primary', 'secondary']
|
||||
|
||||
world.wait_for_present('div.wrapper-prompt.is-shown#prompt-{}'.format(intent))
|
||||
|
||||
action_css = 'li.nav-item > a.action-{}'.format(action)
|
||||
world.trigger_event(action_css, event='focus')
|
||||
world.browser.execute_script("$('{}').click()".format(action_css))
|
||||
|
||||
world.wait_for_ajax_complete()
|
||||
world.wait_for_present('div.wrapper-prompt.is-hiding#prompt-{}'.format(intent))
|
||||
|
||||
|
||||
@world.absorb
|
||||
def confirm_studio_prompt():
|
||||
_do_studio_prompt_action('warning', 'primary')
|
||||
|
||||
|
||||
@step('I confirm the prompt')
|
||||
def confirm_the_prompt(step):
|
||||
|
||||
def click_button(btn_css):
|
||||
world.css_click(btn_css)
|
||||
return world.css_find(btn_css).visible == False
|
||||
|
||||
prompt_css = 'div.prompt.has-actions'
|
||||
world.wait_for_visible(prompt_css)
|
||||
|
||||
btn_css = 'a.button.action-primary'
|
||||
world.wait_for_visible(btn_css)
|
||||
|
||||
# Sometimes you can do a click before the prompt is up.
|
||||
# Thus we need some retry logic here.
|
||||
world.wait_for(lambda _driver: click_button(btn_css))
|
||||
|
||||
assert_false(world.css_find(btn_css).visible)
|
||||
confirm_studio_prompt()
|
||||
|
||||
|
||||
@step(u'I am shown a prompt$')
|
||||
|
||||
@@ -23,8 +23,7 @@ def create_component_instance(step, category, component_type=None, is_advanced=F
|
||||
----------
|
||||
category: component type (discussion, html, problem, video)
|
||||
component_type: for components with multiple templates, the link text in the menu
|
||||
is_advanced: for html and problem, is the desired component under the
|
||||
advanced menu
|
||||
is_advanced: for problems, is the desired component under the advanced menu?
|
||||
"""
|
||||
assert_in(category, ['problem', 'html', 'video', 'discussion'])
|
||||
|
||||
@@ -40,6 +39,8 @@ def create_component_instance(step, category, component_type=None, is_advanced=F
|
||||
# because it's ok if there are currently zero of them.
|
||||
module_count_before = len(world.browser.find_by_css(module_css))
|
||||
|
||||
# Disable the jquery animation for the transition to the menus.
|
||||
world.disable_jquery_animations()
|
||||
world.css_click(component_button_css)
|
||||
|
||||
if category in ('problem', 'html'):
|
||||
@@ -50,17 +51,13 @@ def create_component_instance(step, category, component_type=None, is_advanced=F
|
||||
module_count_before + 1))
|
||||
|
||||
|
||||
@world.absorb
|
||||
def click_new_component_button(step, component_button_css):
|
||||
step.given('I have clicked the new unit button')
|
||||
world.css_click(component_button_css)
|
||||
|
||||
|
||||
def _click_advanced():
|
||||
css = 'ul.problem-type-tabs a[href="#tab2"]'
|
||||
world.css_click(css)
|
||||
my_css = 'ul.problem-type-tabs li.ui-state-active a[href="#tab2"]'
|
||||
assert(world.css_find(my_css))
|
||||
|
||||
# Wait for the advanced tab items to be displayed
|
||||
tab2_css = 'div.ui-tabs-panel#tab2'
|
||||
world.wait_for_visible(tab2_css)
|
||||
|
||||
|
||||
def _find_matching_link(category, component_type):
|
||||
|
||||
@@ -2,22 +2,24 @@
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
from auth.authz import get_course_groupname_for_role, get_user_by_email
|
||||
from nose.tools import assert_true, assert_in # pylint: disable=E0611
|
||||
from nose.tools import assert_in # pylint: disable=E0611
|
||||
|
||||
|
||||
@step(u'(I am viewing|s?he views) the course team settings')
|
||||
@step(u'(I am viewing|s?he views) the course team settings$')
|
||||
def view_grading_settings(_step, whom):
|
||||
world.click_course_settings()
|
||||
link_css = 'li.nav-course-settings-team a'
|
||||
world.css_click(link_css)
|
||||
|
||||
|
||||
@step(u'I add "([^"]*)" to the course team')
|
||||
@step(u'I add "([^"]*)" to the course team$')
|
||||
def add_other_user(_step, name):
|
||||
new_user_css = 'a.create-user-button'
|
||||
world.css_click(new_user_css)
|
||||
world.wait(0.5)
|
||||
|
||||
# Wait for the css animation to apply the is-shown class
|
||||
shown_css = 'div.wrapper-create-user.is-shown'
|
||||
world.wait_for_present(shown_css)
|
||||
|
||||
email_css = 'input#user-email-input'
|
||||
world.css_fill(email_css, name + '@edx.org')
|
||||
@@ -27,35 +29,30 @@ def add_other_user(_step, name):
|
||||
world.css_click(confirm_css)
|
||||
|
||||
|
||||
@step(u'I delete "([^"]*)" from the course team')
|
||||
@step(u'I delete "([^"]*)" from the course team$')
|
||||
def delete_other_user(_step, name):
|
||||
to_delete_css = '.user-item .item-actions a.remove-user[data-id="{email}"]'.format(
|
||||
email="{0}{1}".format(name, '@edx.org'))
|
||||
world.css_click(to_delete_css)
|
||||
# confirm prompt
|
||||
# need to wait for the animation to be done, there isn't a good success condition that won't work both on latest chrome and jenkins
|
||||
world.wait(.5)
|
||||
world.css_click(".wrapper-prompt-warning .action-primary")
|
||||
world.confirm_studio_prompt()
|
||||
|
||||
|
||||
@step(u's?he deletes me from the course team')
|
||||
@step(u's?he deletes me from the course team$')
|
||||
def other_delete_self(_step):
|
||||
to_delete_css = '.user-item .item-actions a.remove-user[data-id="{email}"]'.format(
|
||||
email="robot+studio@edx.org")
|
||||
world.css_click(to_delete_css)
|
||||
# confirm prompt
|
||||
world.wait(.5)
|
||||
world.css_click(".wrapper-prompt-warning .action-primary")
|
||||
world.confirm_studio_prompt()
|
||||
|
||||
|
||||
@step(u'I make "([^"]*)" a course team admin')
|
||||
@step(u'I make "([^"]*)" a course team admin$')
|
||||
def make_course_team_admin(_step, name):
|
||||
admin_btn_css = '.user-item[data-email="{name}@edx.org"] .user-actions .add-admin-role'.format(
|
||||
name=name)
|
||||
world.css_click(admin_btn_css)
|
||||
|
||||
|
||||
@step(u'I remove admin rights from ("([^"]*)"|myself)')
|
||||
@step(u'I remove admin rights from ("([^"]*)"|myself)$')
|
||||
def remove_course_team_admin(_step, outer_capture, name):
|
||||
if outer_capture == "myself":
|
||||
email = world.scenario_dict["USER"].email
|
||||
@@ -66,8 +63,8 @@ def remove_course_team_admin(_step, outer_capture, name):
|
||||
world.css_click(admin_btn_css)
|
||||
|
||||
|
||||
@step(u'I( do not)? see the course on my page')
|
||||
@step(u's?he does( not)? see the course on (his|her) page')
|
||||
@step(u'I( do not)? see the course on my page$')
|
||||
@step(u's?he does( not)? see the course on (his|her) page$')
|
||||
def see_course(_step, do_not_see, gender='self'):
|
||||
class_css = 'h3.course-title'
|
||||
if do_not_see:
|
||||
@@ -78,7 +75,7 @@ def see_course(_step, do_not_see, gender='self'):
|
||||
assert_in(world.scenario_dict['COURSE'].display_name, all_names)
|
||||
|
||||
|
||||
@step(u'"([^"]*)" should( not)? be marked as an admin')
|
||||
@step(u'"([^"]*)" should( not)? be marked as an admin$')
|
||||
def marked_as_admin(_step, name, not_marked_admin):
|
||||
flag_css = '.user-item[data-email="{name}@edx.org"] .flag-role.flag-role-admin'.format(
|
||||
name=name)
|
||||
@@ -88,13 +85,13 @@ def marked_as_admin(_step, name, not_marked_admin):
|
||||
assert world.is_css_present(flag_css)
|
||||
|
||||
|
||||
@step(u'I should( not)? be marked as an admin')
|
||||
@step(u'I should( not)? be marked as an admin$')
|
||||
def self_marked_as_admin(_step, not_marked_admin):
|
||||
return marked_as_admin(_step, "robot+studio", not_marked_admin)
|
||||
|
||||
|
||||
@step(u'I can(not)? delete users')
|
||||
@step(u's?he can(not)? delete users')
|
||||
@step(u'I can(not)? delete users$')
|
||||
@step(u's?he can(not)? delete users$')
|
||||
def can_delete_users(_step, can_not_delete):
|
||||
to_delete_css = 'a.remove-user'
|
||||
if can_not_delete:
|
||||
@@ -103,8 +100,8 @@ def can_delete_users(_step, can_not_delete):
|
||||
assert world.is_css_present(to_delete_css)
|
||||
|
||||
|
||||
@step(u'I can(not)? add users')
|
||||
@step(u's?he can(not)? add users')
|
||||
@step(u'I can(not)? add users$')
|
||||
@step(u's?he can(not)? add users$')
|
||||
def can_add_users(_step, can_not_add):
|
||||
add_css = 'a.create-user-button'
|
||||
if can_not_add:
|
||||
@@ -113,8 +110,8 @@ def can_add_users(_step, can_not_add):
|
||||
assert world.is_css_present(add_css)
|
||||
|
||||
|
||||
@step(u'I can(not)? make ("([^"]*)"|myself) a course team admin')
|
||||
@step(u's?he can(not)? make ("([^"]*)"|me) a course team admin')
|
||||
@step(u'I can(not)? make ("([^"]*)"|myself) a course team admin$')
|
||||
@step(u's?he can(not)? make ("([^"]*)"|me) a course team admin$')
|
||||
def can_make_course_admin(_step, can_not_make_admin, outer_capture, name):
|
||||
if outer_capture == "myself":
|
||||
email = world.scenario_dict["USER"].email
|
||||
|
||||
@@ -6,7 +6,7 @@ from lettuce import world, step
|
||||
from nose.tools import assert_equal, assert_true # pylint: disable=E0611
|
||||
from common import type_in_codemirror, open_new_course
|
||||
from course_import import import_file, go_to_import
|
||||
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
DISPLAY_NAME = "Display Name"
|
||||
MAXIMUM_ATTEMPTS = "Maximum Attempts"
|
||||
@@ -47,9 +47,7 @@ def i_can_modify_the_display_name(_step):
|
||||
# Verifying that the display name can be a string containing a floating point value
|
||||
# (to confirm that we don't throw an error because it is of the wrong type).
|
||||
index = world.get_setting_entry_index(DISPLAY_NAME)
|
||||
world.css_fill('.wrapper-comp-setting .setting-input', '3.4', index=index)
|
||||
if world.is_firefox():
|
||||
world.trigger_event('.wrapper-comp-setting .setting-input', index=index)
|
||||
set_field_value(index, '3.4')
|
||||
verify_modified_display_name()
|
||||
|
||||
|
||||
@@ -62,9 +60,7 @@ def my_display_name_change_is_persisted_on_save(step):
|
||||
@step('I can specify special characters in the display name')
|
||||
def i_can_modify_the_display_name_with_special_chars(_step):
|
||||
index = world.get_setting_entry_index(DISPLAY_NAME)
|
||||
world.css_fill('.wrapper-comp-setting .setting-input', "updated ' \" &", index=index)
|
||||
if world.is_firefox():
|
||||
world.trigger_event('.wrapper-comp-setting .setting-input', index=index)
|
||||
set_field_value(index, "updated ' \" &")
|
||||
verify_modified_display_name_with_special_chars()
|
||||
|
||||
|
||||
@@ -136,11 +132,10 @@ def set_the_weight_to_abc(step, bad_weight):
|
||||
|
||||
@step('if I set the max attempts to "(.*)", it will persist as a valid integer$')
|
||||
def set_the_max_attempts(step, max_attempts_set):
|
||||
# on firefox with selenium, the behaviour is different. eg 2.34 displays as 2.34 and is persisted as 2
|
||||
# on firefox with selenium, the behaviour is different.
|
||||
# eg 2.34 displays as 2.34 and is persisted as 2
|
||||
index = world.get_setting_entry_index(MAXIMUM_ATTEMPTS)
|
||||
world.css_fill('.wrapper-comp-setting .setting-input', max_attempts_set, index=index)
|
||||
if world.is_firefox():
|
||||
world.trigger_event('.wrapper-comp-setting .setting-input', index=index)
|
||||
set_field_value(index, max_attempts_set)
|
||||
world.save_component_and_reopen(step)
|
||||
value = world.css_value('input.setting-input', index=index)
|
||||
assert value != "", "max attempts is blank"
|
||||
@@ -276,12 +271,23 @@ def verify_unset_display_name():
|
||||
world.verify_setting_entry(world.get_setting_entry(DISPLAY_NAME), DISPLAY_NAME, 'Blank Advanced Problem', False)
|
||||
|
||||
|
||||
def set_field_value(index, value):
|
||||
"""
|
||||
Set the field to the specified value.
|
||||
|
||||
Note: we cannot use css_fill here because the value is not set
|
||||
until after you move away from that field.
|
||||
Instead we will find the element, set its value, then hit the Tab key
|
||||
to get to the next field.
|
||||
"""
|
||||
elem = world.css_find('div.wrapper-comp-setting input.setting-input')[index]
|
||||
elem.value = value
|
||||
elem.type(Keys.TAB)
|
||||
|
||||
|
||||
def set_weight(weight):
|
||||
index = world.get_setting_entry_index(PROBLEM_WEIGHT)
|
||||
world.css_fill('.wrapper-comp-setting .setting-input', weight, index=index)
|
||||
if world.is_firefox():
|
||||
world.trigger_event('.wrapper-comp-setting .setting-input', index=index, event='blur')
|
||||
world.trigger_event('a.save-button', event='focus')
|
||||
set_field_value(index, weight)
|
||||
|
||||
|
||||
def open_high_level_source():
|
||||
|
||||
@@ -88,11 +88,7 @@ def delete_file(_step, file_name):
|
||||
assert index != -1
|
||||
delete_css = "a.remove-asset-button"
|
||||
world.css_click(delete_css, index=index)
|
||||
|
||||
world.wait_for_present(".wrapper-prompt.is-shown")
|
||||
world.wait(0.2) # wait for css animation
|
||||
prompt_confirm_css = 'li.nav-item > a.action-primary'
|
||||
world.css_click(prompt_confirm_css)
|
||||
world.confirm_studio_prompt()
|
||||
|
||||
|
||||
@step(u'I should see only one "([^"]*)"$')
|
||||
|
||||
@@ -223,7 +223,20 @@ def wait_for_ajax_complete():
|
||||
}
|
||||
}, 100);
|
||||
"""
|
||||
world.browser.driver.execute_async_script(dedent(javascript))
|
||||
# Sometimes the ajax when it returns will make the browser reload
|
||||
# the DOM, and throw a WebDriverException with the message:
|
||||
# 'javascript error: document unloaded while waiting for result'
|
||||
for _ in range(5): # 5 attempts max
|
||||
try:
|
||||
result = world.browser.driver.execute_async_script(dedent(javascript))
|
||||
except WebDriverException as wde:
|
||||
if "document unloaded while waiting for result" in wde.msg:
|
||||
# Wait a bit, and try again, when the browser has reloaded the page.
|
||||
world.wait(1)
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
return result
|
||||
|
||||
|
||||
@world.absorb
|
||||
@@ -268,9 +281,9 @@ def css_has_text(css_selector, text, index=0, strip=False):
|
||||
# If we're expecting a non-empty string, give the page
|
||||
# a chance to fill in text fields.
|
||||
if text:
|
||||
world.wait_for(lambda _: world.css_text(css_selector, index=index))
|
||||
wait_for(lambda _: css_text(css_selector, index=index))
|
||||
|
||||
actual_text = world.css_text(css_selector, index=index)
|
||||
actual_text = css_text(css_selector, index=index)
|
||||
|
||||
if strip:
|
||||
actual_text = actual_text.strip()
|
||||
@@ -291,88 +304,76 @@ def css_has_value(css_selector, value, index=0):
|
||||
# If we're expecting a non-empty string, give the page
|
||||
# a chance to fill in values
|
||||
if value:
|
||||
world.wait_for(lambda _: world.css_value(css_selector, index=index))
|
||||
wait_for(lambda _: css_value(css_selector, index=index))
|
||||
|
||||
return world.css_value(css_selector, index=index) == value
|
||||
return css_value(css_selector, index=index) == value
|
||||
|
||||
|
||||
@world.absorb
|
||||
def wait_for(func, timeout=5):
|
||||
WebDriverWait(
|
||||
driver=world.browser.driver,
|
||||
timeout=timeout,
|
||||
ignored_exceptions=(StaleElementReferenceException)
|
||||
).until(func)
|
||||
def wait_for(func, timeout=5, timeout_msg=None):
|
||||
"""
|
||||
Calls the method provided with the driver as an argument until the
|
||||
return value is not False.
|
||||
Throws an error if the WebDriverWait timeout clock expires.
|
||||
Otherwise this method will return None.
|
||||
"""
|
||||
msg = timeout_msg or "Timed out after {} seconds.".format(timeout)
|
||||
try:
|
||||
WebDriverWait(
|
||||
driver=world.browser.driver,
|
||||
timeout=timeout,
|
||||
ignored_exceptions=(StaleElementReferenceException)
|
||||
).until(func)
|
||||
except TimeoutException:
|
||||
raise TimeoutException(msg)
|
||||
|
||||
|
||||
@world.absorb
|
||||
def wait_for_present(css_selector, timeout=30):
|
||||
"""
|
||||
Waiting for the element to be present in the DOM.
|
||||
Throws an error if the WebDriverWait timeout clock expires.
|
||||
Otherwise this method will return None
|
||||
Wait for the element to be present in the DOM.
|
||||
"""
|
||||
try:
|
||||
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))
|
||||
wait_for(
|
||||
func=lambda _: EC.presence_of_element_located((By.CSS_SELECTOR, css_selector,)),
|
||||
timeout=timeout,
|
||||
timeout_msg="Timed out waiting for {} to be present.".format(css_selector)
|
||||
)
|
||||
|
||||
|
||||
@world.absorb
|
||||
def wait_for_visible(css_selector, timeout=30):
|
||||
def wait_for_visible(css_selector, index=0, timeout=30):
|
||||
"""
|
||||
Waiting for the element to be visible in the DOM.
|
||||
Throws an error if the WebDriverWait timeout clock expires.
|
||||
Otherwise this method will return None
|
||||
Wait for the element to be visible in the DOM.
|
||||
"""
|
||||
try:
|
||||
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))
|
||||
wait_for(
|
||||
func=lambda _: css_visible(css_selector, index),
|
||||
timeout=timeout,
|
||||
timeout_msg="Timed out waiting for {} to be visible.".format(css_selector)
|
||||
)
|
||||
|
||||
|
||||
@world.absorb
|
||||
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 WebDriverWait timeout clock expires.
|
||||
Otherwise this method will return None
|
||||
Wait for the element to be either invisible or not present on the DOM.
|
||||
"""
|
||||
try:
|
||||
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))
|
||||
wait_for(
|
||||
func=lambda _: EC.invisibility_of_element_located((By.CSS_SELECTOR, css_selector,)),
|
||||
timeout=timeout,
|
||||
timeout_msg="Timed out waiting for {} to be invisible.".format(css_selector)
|
||||
)
|
||||
|
||||
|
||||
@world.absorb
|
||||
def wait_for_clickable(css_selector, timeout=30):
|
||||
"""
|
||||
Waiting for the element to be present and clickable.
|
||||
Throws an error if the WebDriverWait timeout clock expires.
|
||||
Otherwise this method will return None.
|
||||
Wait for the element to be present and clickable.
|
||||
"""
|
||||
# Sometimes the element is clickable then gets obscured.
|
||||
# In this case, pause so that it is not reported clickable too early
|
||||
try:
|
||||
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))
|
||||
wait_for(
|
||||
func=lambda _: EC.element_to_be_clickable((By.CSS_SELECTOR, css_selector,)),
|
||||
timeout=timeout,
|
||||
timeout_msg="Timed out waiting for {} to be clickable.".format(css_selector)
|
||||
)
|
||||
|
||||
|
||||
@world.absorb
|
||||
@@ -396,12 +397,13 @@ def css_click(css_selector, index=0, wait_time=30):
|
||||
This method will return True if the click worked.
|
||||
"""
|
||||
wait_for_clickable(css_selector, timeout=wait_time)
|
||||
wait_for_visible(css_selector, index=index, timeout=wait_time)
|
||||
assert_true(
|
||||
world.css_visible(css_selector, index=index),
|
||||
css_visible(css_selector, index=index),
|
||||
msg="Element {}[{}] is present but not visible".format(css_selector, index)
|
||||
)
|
||||
|
||||
result = retry_on_exception(lambda: world.css_find(css_selector)[index].click())
|
||||
result = retry_on_exception(lambda: css_find(css_selector)[index].click())
|
||||
if result:
|
||||
wait_for_js_to_load()
|
||||
return result
|
||||
@@ -453,6 +455,7 @@ def css_fill(css_selector, text, index=0):
|
||||
Note that this will replace the current value completely.
|
||||
Then for synchronization purposes, wait for the value on the page.
|
||||
"""
|
||||
wait_for_visible(css_selector, index=index)
|
||||
retry_on_exception(lambda: css_find(css_selector)[index].fill(text))
|
||||
wait_for(lambda _: css_has_value(css_selector, text, index=index))
|
||||
return True
|
||||
@@ -525,19 +528,19 @@ def save_the_html(path='/tmp'):
|
||||
@world.absorb
|
||||
def click_course_content():
|
||||
course_content_css = 'li.nav-course-courseware'
|
||||
world.css_click(course_content_css)
|
||||
css_click(course_content_css)
|
||||
|
||||
|
||||
@world.absorb
|
||||
def click_course_settings():
|
||||
course_settings_css = 'li.nav-course-settings'
|
||||
world.css_click(course_settings_css)
|
||||
css_click(course_settings_css)
|
||||
|
||||
|
||||
@world.absorb
|
||||
def click_tools():
|
||||
tools_css = 'li.nav-course-tools'
|
||||
world.css_click(tools_css)
|
||||
css_click(tools_css)
|
||||
|
||||
|
||||
@world.absorb
|
||||
|
||||
@@ -78,6 +78,7 @@ def select_the_verified_track(step):
|
||||
create_cert_course()
|
||||
register()
|
||||
select_contribution(32)
|
||||
world.wait_for_ajax_complete()
|
||||
btn_css = 'input[value="Select Certificate"]'
|
||||
world.css_click(btn_css)
|
||||
assert world.is_css_present('section.progress')
|
||||
@@ -174,6 +175,9 @@ def at_the_payment_page(step):
|
||||
|
||||
@step(u'I submit valid payment information$')
|
||||
def submit_payment(step):
|
||||
# First make sure that the page is done if it still executing
|
||||
# an ajax query.
|
||||
world.wait_for_ajax_complete()
|
||||
button_css = 'input[value=Submit]'
|
||||
world.css_click(button_css)
|
||||
|
||||
|
||||
@@ -180,7 +180,6 @@ Feature: LMS.Answer problems
|
||||
Given I am viewing a "<ProblemType>" problem
|
||||
Then my "<ProblemType>" answer is marked "unanswered"
|
||||
When I answer a "<ProblemType>" problem "<InitialCorrectness>ly"
|
||||
And I wait for "1" seconds
|
||||
And I input an answer on a "<ProblemType>" problem "<OtherCorrectness>ly"
|
||||
Then my "<ProblemType>" answer is marked "unanswered"
|
||||
And I reset the problem
|
||||
@@ -208,7 +207,6 @@ Feature: LMS.Answer problems
|
||||
Scenario: I can reset the correctness of a radiogroup problem after changing my answer
|
||||
Given I am viewing a "<ProblemType>" problem
|
||||
When I answer a "<ProblemType>" problem "<InitialCorrectness>ly"
|
||||
And I wait for "1" seconds
|
||||
Then my "<ProblemType>" answer is marked "<InitialCorrectness>"
|
||||
And I input an answer on a "<ProblemType>" problem "<OtherCorrectness>ly"
|
||||
Then my "<ProblemType>" answer is NOT marked "<InitialCorrectness>"
|
||||
|
||||
@@ -163,6 +163,10 @@ PROBLEM_DICT = {
|
||||
|
||||
|
||||
def answer_problem(problem_type, correctness):
|
||||
# Make sure that the problem has been completely rendered before
|
||||
# starting to input an answer.
|
||||
world.wait_for_ajax_complete()
|
||||
|
||||
if problem_type == "drop down":
|
||||
select_name = "input_i4x-edx-model_course-problem-drop_down_2_1"
|
||||
option_text = 'Option 2' if correctness == 'correct' else 'Option 3'
|
||||
|
||||
Reference in New Issue
Block a user