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"
DISPLAY_NAME_VALUE = '"Robot Super Course"'
############### ACTIONS ####################
@step('I select the Advanced Settings$')
def i_select_advanced_settings(step):
world.click_course_settings()
......@@ -45,7 +44,6 @@ def create_value_not_in_quotes(step):
change_display_name_value(step, 'quote me')
############### RESULTS ####################
@step('I see default advanced settings$')
def i_see_default_advanced_settings(step):
# 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):
assert_equal(get_display_name_value(), '"foo"')
############# HELPERS ###############
def assert_policy_entries(expected_keys, expected_values):
for key, value in zip(expected_keys, expected_values):
index = get_index_of(key)
assert_false(index == -1, "Could not find key: {key}".format(key=key))
found_value = world.css_find(VALUE_CSS)[index].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):
......
......@@ -165,7 +165,7 @@ def log_into_studio(
world.log_in(username=uname, password=password, email=email, name=name)
# Navigate to the studio dashboard
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():
......
......@@ -110,9 +110,9 @@ def other_user_login(_step, name):
@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, inverted, gender='self'):
def see_course(_step, do_not_see, gender='self'):
class_css = 'h3.course-title'
if inverted:
if do_not_see:
assert world.is_css_not_present(class_css)
else:
all_courses = world.css_find(class_css)
......@@ -121,25 +121,25 @@ def see_course(_step, inverted, gender='self'):
@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(
email=name+EMAIL_EXTENSION)
if inverted:
if not_marked_admin:
assert world.is_css_not_present(flag_css)
else:
assert world.is_css_present(flag_css)
@step(u'I should( not)? be marked as an admin')
def self_marked_as_admin(_step, inverted):
return marked_as_admin(_step, "robot+studio", inverted)
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')
def can_delete_users(_step, inverted):
def can_delete_users(_step, can_not_delete):
to_delete_css = 'a.remove-user'
if inverted:
if can_not_delete:
assert world.is_css_not_present(to_delete_css)
else:
assert world.is_css_present(to_delete_css)
......@@ -147,9 +147,9 @@ def can_delete_users(_step, inverted):
@step(u'I 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'
if inverted:
if can_not_add:
assert world.is_css_not_present(add_css)
else:
assert world.is_css_present(add_css)
......@@ -157,13 +157,13 @@ def can_add_users(_step, inverted):
@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, inverted, outer_capture, name):
def can_make_course_admin(_step, can_not_make_admin, outer_capture, name):
if outer_capture == "myself":
email = world.scenario_dict["USER"].email
else:
email = name + EMAIL_EXTENSION
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)
else:
assert world.is_css_present(add_button_css)
......@@ -82,9 +82,9 @@ def see_assignment_name(step, do_not, name):
assignment_menu = world.css_find(assignment_menu_css)
allnames = [item.html for item in assignment_menu]
if do_not:
assert_not_in (name, allnames)
assert_not_in(name, allnames)
else:
assert_in (name, allnames)
assert_in(name, allnames)
@step(u'I delete the assignment type "([^"]*)"$')
......
......@@ -2,7 +2,7 @@
#pylint: disable=C0111
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
DISPLAY_NAME = "Display Name"
......@@ -198,14 +198,19 @@ def high_level_source_in_editor(step):
def verify_high_level_source_links(step, 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:
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)
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:
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():
......
......@@ -88,7 +88,6 @@ def initial_setup(server):
"""
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')
if not world.SAUCE_ENABLED:
......@@ -166,15 +165,18 @@ def reset_databases(scenario):
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):
"""
Save a screenshot to help with debugging.
"""
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
def teardown_browser(total):
......
......@@ -5,7 +5,7 @@ from lettuce import world
import time
import platform
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.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
......@@ -54,8 +54,11 @@ def wait_for_present(css_selector, timeout=30):
Throws an error if the wait_for time expires.
Otherwise this method will return None
"""
WebDriverWait(driver=world.browser.driver,
timeout=60).until(EC.presence_of_element_located((By.CSS_SELECTOR, css_selector,)))
try:
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
......@@ -65,8 +68,11 @@ def wait_for_visible(css_selector, timeout=30):
Throws an error if the wait_for time expires.
Otherwise this method will return None
"""
WebDriverWait(driver=world.browser.driver,
timeout=timeout).until(EC.visibility_of_element_located((By.CSS_SELECTOR, css_selector,)))
try:
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
......@@ -76,8 +82,11 @@ def wait_for_invisible(css_selector, timeout=30):
Throws an error if the wait_for time expires.
Otherwise this method will return None
"""
WebDriverWait(driver=world.browser.driver,
timeout=timeout).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, css_selector,)))
try:
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
......@@ -89,8 +98,11 @@ def wait_for_clickable(css_selector, timeout=30):
"""
# Sometimes the element is clickable then gets obscured.
# In this case, pause so that it is not reported clickable too early
WebDriverWait(world.browser.driver,
timeout=timeout).until(EC.element_to_be_clickable((By.CSS_SELECTOR, css_selector,)))
try:
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
......@@ -114,7 +126,8 @@ 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)
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
# 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):
'''
wait_for_clickable(css_selector, timeout=timeout)
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.click()
......@@ -158,7 +172,7 @@ def id_click(elem_id):
"""
Perform a click on an element as specified by its id
"""
css_click('#%s' % elem_id)
css_click('#{}'.format(elem_id))
@world.absorb
......
......@@ -80,8 +80,8 @@ def click_on_section(step, section):
section_css = 'h3[tabindex="-1"]'
world.css_click(section_css)
subid = "ui-accordion-accordion-panel-" + str(int(section) - 1)
subsection_css = 'ul.ui-accordion-content-active[id=\'%s\'] > li > a' % subid
subid = "ui-accordion-accordion-panel-{}".format(str(int(section) - 1))
subsection_css = "ul.ui-accordion-content-active[id='{}'] > li > a".format(subid)
world.css_click(subsection_css)
......
......@@ -166,6 +166,8 @@ def answer_problem(problem_type, correctness):
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'
# 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)
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