Commit 30b13d3c by Jay Zoldak

Improve code clarity and error messages for css selection

parent 2ff056df
...@@ -11,7 +11,6 @@ DISPLAY_NAME_KEY = "display_name" ...@@ -11,7 +11,6 @@ DISPLAY_NAME_KEY = "display_name"
DISPLAY_NAME_VALUE = '"Robot Super Course"' DISPLAY_NAME_VALUE = '"Robot Super Course"'
############### ACTIONS ####################
@step('I select the Advanced Settings$') @step('I select the Advanced Settings$')
def i_select_advanced_settings(step): def i_select_advanced_settings(step):
world.click_course_settings() world.click_course_settings()
...@@ -45,7 +44,6 @@ def create_value_not_in_quotes(step): ...@@ -45,7 +44,6 @@ def create_value_not_in_quotes(step):
change_display_name_value(step, 'quote me') change_display_name_value(step, 'quote me')
############### RESULTS ####################
@step('I see default advanced settings$') @step('I see default advanced settings$')
def i_see_default_advanced_settings(step): def i_see_default_advanced_settings(step):
# Test only a few of the existing properties (there are around 34 of them) # Test only a few of the existing properties (there are around 34 of them)
...@@ -88,14 +86,13 @@ def the_policy_key_value_is_changed(step): ...@@ -88,14 +86,13 @@ def the_policy_key_value_is_changed(step):
assert_equal(get_display_name_value(), '"foo"') assert_equal(get_display_name_value(), '"foo"')
############# HELPERS ###############
def assert_policy_entries(expected_keys, expected_values): def assert_policy_entries(expected_keys, expected_values):
for key, value in zip(expected_keys, expected_values): for key, value in zip(expected_keys, expected_values):
index = get_index_of(key) index = get_index_of(key)
assert_false(index == -1, "Could not find key: {key}".format(key=key)) assert_false(index == -1, "Could not find key: {key}".format(key=key))
found_value = world.css_find(VALUE_CSS)[index].value found_value = world.css_find(VALUE_CSS)[index].value
assert_equal(value, found_value, assert_equal(value, found_value,
"{} is not equal to {}".format(value, found_value)) "Expected {} to have value {} but found {}".format(key, value, found_value))
def get_index_of(expected_key): def get_index_of(expected_key):
......
...@@ -165,7 +165,7 @@ def log_into_studio( ...@@ -165,7 +165,7 @@ def log_into_studio(
world.log_in(username=uname, password=password, email=email, name=name) world.log_in(username=uname, password=password, email=email, name=name)
# Navigate to the studio dashboard # Navigate to the studio dashboard
world.visit('/') world.visit('/')
assert_in(uname, world.css_text('h2.title', timeout=60)) assert_in(uname, world.css_text('h2.title', timeout=10))
def create_a_course(): def create_a_course():
......
...@@ -110,9 +110,9 @@ def other_user_login(_step, name): ...@@ -110,9 +110,9 @@ def other_user_login(_step, name):
@step(u'I( do not)? see the course on my 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') @step(u's?he does( not)? see the course on (his|her) page')
def see_course(_step, inverted, gender='self'): def see_course(_step, do_not_see, gender='self'):
class_css = 'h3.course-title' class_css = 'h3.course-title'
if inverted: if do_not_see:
assert world.is_css_not_present(class_css) assert world.is_css_not_present(class_css)
else: else:
all_courses = world.css_find(class_css) all_courses = world.css_find(class_css)
...@@ -121,25 +121,25 @@ def see_course(_step, inverted, gender='self'): ...@@ -121,25 +121,25 @@ def see_course(_step, inverted, gender='self'):
@step(u'"([^"]*)" should( not)? be marked as an admin') @step(u'"([^"]*)" should( not)? be marked as an admin')
def marked_as_admin(_step, name, inverted): def marked_as_admin(_step, name, not_marked_admin):
flag_css = '.user-item[data-email="{email}"] .flag-role.flag-role-admin'.format( flag_css = '.user-item[data-email="{email}"] .flag-role.flag-role-admin'.format(
email=name+EMAIL_EXTENSION) email=name+EMAIL_EXTENSION)
if inverted: if not_marked_admin:
assert world.is_css_not_present(flag_css) assert world.is_css_not_present(flag_css)
else: else:
assert world.is_css_present(flag_css) 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, inverted): def self_marked_as_admin(_step, not_marked_admin):
return marked_as_admin(_step, "robot+studio", inverted) return marked_as_admin(_step, "robot+studio", not_marked_admin)
@step(u'I can(not)? delete users') @step(u'I can(not)? delete users')
@step(u's?he can(not)? delete users') @step(u's?he can(not)? delete users')
def can_delete_users(_step, inverted): def can_delete_users(_step, can_not_delete):
to_delete_css = 'a.remove-user' to_delete_css = 'a.remove-user'
if inverted: if can_not_delete:
assert world.is_css_not_present(to_delete_css) assert world.is_css_not_present(to_delete_css)
else: else:
assert world.is_css_present(to_delete_css) assert world.is_css_present(to_delete_css)
...@@ -147,9 +147,9 @@ def can_delete_users(_step, inverted): ...@@ -147,9 +147,9 @@ def can_delete_users(_step, inverted):
@step(u'I can(not)? add users') @step(u'I can(not)? add users')
@step(u's?he can(not)? add users') @step(u's?he can(not)? add users')
def can_add_users(_step, inverted): def can_add_users(_step, can_not_add):
add_css = 'a.create-user-button' add_css = 'a.create-user-button'
if inverted: if can_not_add:
assert world.is_css_not_present(add_css) assert world.is_css_not_present(add_css)
else: else:
assert world.is_css_present(add_css) assert world.is_css_present(add_css)
...@@ -157,13 +157,13 @@ def can_add_users(_step, inverted): ...@@ -157,13 +157,13 @@ def can_add_users(_step, inverted):
@step(u'I can(not)? make ("([^"]*)"|myself) 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') @step(u's?he can(not)? make ("([^"]*)"|me) a course team admin')
def can_make_course_admin(_step, inverted, outer_capture, name): def can_make_course_admin(_step, can_not_make_admin, outer_capture, name):
if outer_capture == "myself": if outer_capture == "myself":
email = world.scenario_dict["USER"].email email = world.scenario_dict["USER"].email
else: else:
email = name + EMAIL_EXTENSION email = name + EMAIL_EXTENSION
add_button_css = '.user-item[data-email="{email}"] .add-admin-role'.format(email=email) add_button_css = '.user-item[data-email="{email}"] .add-admin-role'.format(email=email)
if inverted: if can_not_make_admin:
assert world.is_css_not_present(add_button_css) assert world.is_css_not_present(add_button_css)
else: else:
assert world.is_css_present(add_button_css) assert world.is_css_present(add_button_css)
...@@ -82,9 +82,9 @@ def see_assignment_name(step, do_not, name): ...@@ -82,9 +82,9 @@ def see_assignment_name(step, do_not, name):
assignment_menu = world.css_find(assignment_menu_css) assignment_menu = world.css_find(assignment_menu_css)
allnames = [item.html for item in assignment_menu] allnames = [item.html for item in assignment_menu]
if do_not: if do_not:
assert_not_in (name, allnames) assert_not_in(name, allnames)
else: else:
assert_in (name, allnames) assert_in(name, allnames)
@step(u'I delete the assignment type "([^"]*)"$') @step(u'I delete the assignment type "([^"]*)"$')
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#pylint: disable=C0111 #pylint: disable=C0111
from lettuce import world, step from lettuce import world, step
from nose.tools import assert_equal # pylint: disable=E0611 from nose.tools import assert_equal, assert_true # pylint: disable=E0611
from common import type_in_codemirror from common import type_in_codemirror
DISPLAY_NAME = "Display Name" DISPLAY_NAME = "Display Name"
...@@ -198,14 +198,19 @@ def high_level_source_in_editor(step): ...@@ -198,14 +198,19 @@ def high_level_source_in_editor(step):
def verify_high_level_source_links(step, visible): def verify_high_level_source_links(step, visible):
if visible: if visible:
assert world.is_css_present('.launch-latex-compiler') assert_true(world.is_css_present('.launch-latex-compiler'),
msg="Expected to find the latex button but it is not present.")
else: else:
assert world.is_css_not_present('.launch-latex-compiler') assert_true(world.is_css_not_present('.launch-latex-compiler'),
msg="Expected not to find the latex button but it is present.")
world.cancel_component(step) world.cancel_component(step)
if visible: if visible:
assert world.is_css_present('.upload-button') assert_true(world.is_css_present('.upload-button'),
msg="Expected to find the upload button but it is not present.")
else: else:
assert world.is_css_not_present('.upload-button') assert_true(world.is_css_not_present('.upload-button'),
msg="Expected not to find the upload button but it is present.")
def verify_modified_weight(): def verify_modified_weight():
......
...@@ -88,7 +88,6 @@ def initial_setup(server): ...@@ -88,7 +88,6 @@ def initial_setup(server):
""" """
Launch the browser once before executing the tests. Launch the browser once before executing the tests.
""" """
# from nose.tools import set_trace; set_trace()
world.absorb(settings.SAUCE.get('SAUCE_ENABLED'), 'SAUCE_ENABLED') world.absorb(settings.SAUCE.get('SAUCE_ENABLED'), 'SAUCE_ENABLED')
if not world.SAUCE_ENABLED: if not world.SAUCE_ENABLED:
...@@ -166,15 +165,18 @@ def reset_databases(scenario): ...@@ -166,15 +165,18 @@ def reset_databases(scenario):
xmodule.modulestore.django.clear_existing_modulestores() xmodule.modulestore.django.clear_existing_modulestores()
# Uncomment below to trigger a screenshot on error @after.each_scenario
# @after.each_scenario
def screenshot_on_error(scenario): def screenshot_on_error(scenario):
""" """
Save a screenshot to help with debugging. Save a screenshot to help with debugging.
""" """
if scenario.failed: if scenario.failed:
world.browser.driver.save_screenshot('/tmp/last_failed_scenario.png') try:
output_dir = '{}/log'.format(settings.TEST_ROOT)
image_name = '{}/{}.png'.format(output_dir, scenario.name.replace(' ', '_'))
world.browser.driver.save_screenshot(image_name)
except WebDriverException:
LOGGER.error('Could not capture a screenshot')
@after.all @after.all
def teardown_browser(total): def teardown_browser(total):
......
...@@ -5,7 +5,7 @@ from lettuce import world ...@@ -5,7 +5,7 @@ from lettuce import world
import time import time
import platform import platform
from urllib import quote_plus from urllib import quote_plus
from selenium.common.exceptions import WebDriverException from selenium.common.exceptions import WebDriverException, TimeoutException
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
...@@ -54,8 +54,11 @@ def wait_for_present(css_selector, timeout=30): ...@@ -54,8 +54,11 @@ def wait_for_present(css_selector, timeout=30):
Throws an error if the wait_for time expires. Throws an error if the wait_for time expires.
Otherwise this method will return None Otherwise this method will return None
""" """
WebDriverWait(driver=world.browser.driver, try:
timeout=60).until(EC.presence_of_element_located((By.CSS_SELECTOR, css_selector,))) WebDriverWait(driver=world.browser.driver,
timeout=60).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))
@world.absorb @world.absorb
...@@ -65,8 +68,11 @@ def wait_for_visible(css_selector, timeout=30): ...@@ -65,8 +68,11 @@ def wait_for_visible(css_selector, timeout=30):
Throws an error if the wait_for time expires. Throws an error if the wait_for time expires.
Otherwise this method will return None Otherwise this method will return None
""" """
WebDriverWait(driver=world.browser.driver, try:
timeout=timeout).until(EC.visibility_of_element_located((By.CSS_SELECTOR, css_selector,))) WebDriverWait(driver=world.browser.driver,
timeout=timeout).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))
@world.absorb @world.absorb
...@@ -76,8 +82,11 @@ def wait_for_invisible(css_selector, timeout=30): ...@@ -76,8 +82,11 @@ def wait_for_invisible(css_selector, timeout=30):
Throws an error if the wait_for time expires. Throws an error if the wait_for time expires.
Otherwise this method will return None Otherwise this method will return None
""" """
WebDriverWait(driver=world.browser.driver, try:
timeout=timeout).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, css_selector,))) WebDriverWait(driver=world.browser.driver,
timeout=timeout).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))
@world.absorb @world.absorb
...@@ -89,8 +98,11 @@ def wait_for_clickable(css_selector, timeout=30): ...@@ -89,8 +98,11 @@ def wait_for_clickable(css_selector, timeout=30):
""" """
# Sometimes the element is clickable then gets obscured. # Sometimes the element is clickable then gets obscured.
# In this case, pause so that it is not reported clickable too early # In this case, pause so that it is not reported clickable too early
WebDriverWait(world.browser.driver, try:
timeout=timeout).until(EC.element_to_be_clickable((By.CSS_SELECTOR, css_selector,))) WebDriverWait(world.browser.driver,
timeout=timeout).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))
@world.absorb @world.absorb
...@@ -114,7 +126,8 @@ def css_click(css_selector, index=0, wait_time=30): ...@@ -114,7 +126,8 @@ def css_click(css_selector, index=0, wait_time=30):
This method will return True if the click worked. This method will return True if the click worked.
""" """
wait_for_clickable(css_selector, timeout=wait_time) wait_for_clickable(css_selector, timeout=wait_time)
assert world.css_find(css_selector)[index].visible assert_true(world.css_find(css_selector)[index].visible,
msg="Element {}[{}] is present but not visible".format(css_selector, index))
# Sometimes you can't click in the center of the element, as # Sometimes you can't click in the center of the element, as
# another element might be on top of it. In this case, try # another element might be on top of it. In this case, try
...@@ -146,7 +159,8 @@ def css_click_at(css_selector, index=0, x_coord=10, y_coord=10, timeout=5): ...@@ -146,7 +159,8 @@ def css_click_at(css_selector, index=0, x_coord=10, y_coord=10, timeout=5):
''' '''
wait_for_clickable(css_selector, timeout=timeout) wait_for_clickable(css_selector, timeout=timeout)
element = css_find(css_selector)[index] element = css_find(css_selector)[index]
assert element.visible assert_true(element.visible,
msg="Element {}[{}] is present but not visible".format(css_selector, index))
element.action_chains.move_to_element_with_offset(element._element, x_coord, y_coord) element.action_chains.move_to_element_with_offset(element._element, x_coord, y_coord)
element.action_chains.click() element.action_chains.click()
...@@ -158,7 +172,7 @@ def id_click(elem_id): ...@@ -158,7 +172,7 @@ def id_click(elem_id):
""" """
Perform a click on an element as specified by its id Perform a click on an element as specified by its id
""" """
css_click('#%s' % elem_id) css_click('#{}'.format(elem_id))
@world.absorb @world.absorb
......
...@@ -80,8 +80,8 @@ def click_on_section(step, section): ...@@ -80,8 +80,8 @@ def click_on_section(step, section):
section_css = 'h3[tabindex="-1"]' section_css = 'h3[tabindex="-1"]'
world.css_click(section_css) world.css_click(section_css)
subid = "ui-accordion-accordion-panel-" + str(int(section) - 1) subid = "ui-accordion-accordion-panel-{}".format(str(int(section) - 1))
subsection_css = 'ul.ui-accordion-content-active[id=\'%s\'] > li > a' % subid subsection_css = "ul.ui-accordion-content-active[id='{}'] > li > a".format(subid)
world.css_click(subsection_css) world.css_click(subsection_css)
......
...@@ -166,6 +166,8 @@ def answer_problem(problem_type, correctness): ...@@ -166,6 +166,8 @@ def answer_problem(problem_type, correctness):
if problem_type == "drop down": if problem_type == "drop down":
select_name = "input_i4x-edx-model_course-problem-drop_down_2_1" select_name = "input_i4x-edx-model_course-problem-drop_down_2_1"
option_text = 'Option 2' if correctness == 'correct' else 'Option 3' option_text = 'Option 2' if correctness == 'correct' else 'Option 3'
# First wait for the element to be there on the page
world.wait_for_visible("select#{}".format(select_name))
world.browser.select(select_name, option_text) world.browser.select(select_name, option_text)
elif problem_type == "multiple choice": elif problem_type == "multiple choice":
......
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