Commit 2ff056df by Jay Zoldak

Simplify retry logic for ui helper functions

parent 50f190c5
......@@ -93,7 +93,9 @@ 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))
assert_equal(value, world.css_find(VALUE_CSS)[index].value, "value is incorrect")
found_value = world.css_find(VALUE_CSS)[index].value
assert_equal(value, found_value,
"{} is not equal to {}".format(value, found_value))
def get_index_of(expected_key):
......
......@@ -2,7 +2,7 @@
# pylint: disable=W0621
from lettuce import world, step
from nose.tools import assert_true # pylint: disable=E0611
from nose.tools import assert_true, assert_in, assert_false # pylint: disable=E0611
from auth.authz import get_user_by_email, get_course_groupname_for_role
from django.conf import settings
......@@ -19,8 +19,6 @@ from terrain.browser import reset_data
TEST_ROOT = settings.COMMON_TEST_DATA_ROOT
########### STEP HELPERS ##############
@step('I (?:visit|access|open) the Studio homepage$')
def i_visit_the_studio_homepage(_step):
......@@ -66,20 +64,32 @@ def select_new_course(_step, whom):
@step(u'I press the "([^"]*)" notification button$')
def press_the_notification_button(_step, name):
css = 'a.action-%s' % name.lower()
# The button was clicked if either the notification bar is gone,
# or we see an error overlaying it (expected for invalid inputs).
def button_clicked():
confirmation_dismissed = world.is_css_not_present('.is-shown.wrapper-notification-warning')
error_showing = world.is_css_present('.is-shown.wrapper-notification-error')
return confirmation_dismissed or error_showing
# TODO: fix up this code. Selenium is not dealing well with css transforms,
# as it thinks that the notification and the buttons are always visible
# First wait for the notification to pop up
notification_css = 'div#page-notification div.wrapper-notification'
world.wait_for_visible(notification_css)
# You would think that the above would have worked, but it doesn't.
# Brute force wait for now.
world.wait(.5)
# Now make sure the button is there
btn_css = 'div#page-notification a.action-%s' % name.lower()
world.wait_for_visible(btn_css)
# You would think that the above would have worked, but it doesn't.
# Brute force wait for now.
world.wait(.5)
if world.is_firefox():
# This is done to explicitly make the changes save on firefox. It will remove focus from the previously focused element
world.trigger_event(css, event='focus')
world.browser.execute_script("$('{}').click()".format(css))
# This is done to explicitly make the changes save on firefox.
# It will remove focus from the previously focused element
world.trigger_event(btn_css, event='focus')
world.browser.execute_script("$('{}').click()".format(btn_css))
else:
world.css_click(css, success_condition=button_clicked), '%s button not clicked after 5 attempts.' % name
world.css_click(btn_css)
@step('I change the "(.*)" field to "(.*)"$')
......@@ -110,7 +120,6 @@ def i_see_a_confirmation(step):
assert world.is_css_present(confirmation_css)
####### HELPER FUNCTIONS ##############
def open_new_course():
world.clear_courses()
create_studio_user()
......@@ -156,8 +165,8 @@ 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 uname in world.css_text('h2.title', max_attempts=15)
def create_a_course():
course = world.CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
......@@ -247,8 +256,22 @@ def button_disabled(step, value):
@step('I confirm the prompt')
def confirm_the_prompt(step):
prompt_css = 'a.button.action-primary'
world.css_click(prompt_css, success_condition=lambda: not world.css_visible(prompt_css))
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)
@step(u'I am shown a (.*)$')
......@@ -257,6 +280,7 @@ def i_am_shown_a_notification(step, notification_type):
def type_in_codemirror(index, text):
world.wait(1) # For now, slow this down so that it works. TODO: fix it.
world.css_click("div.CodeMirror-lines", index=index)
world.browser.execute_script("$('div.CodeMirror.CodeMirror-focused > div').css('overflow', '')")
g = world.css_find("div.CodeMirror.CodeMirror-focused > div > textarea")
......
......@@ -48,9 +48,7 @@ def click_component_from_menu(category, boilerplate, expected_css):
elem_css = "a[data-category='{}']:not([data-boilerplate])".format(category)
elements = world.css_find(elem_css)
assert_equal(len(elements), 1)
world.wait_for(lambda _driver: world.css_visible(elem_css))
world.css_click(elem_css, success_condition=lambda: 1 == len(world.css_find(expected_css)))
world.css_click(elem_css)
@world.absorb
def edit_component_and_select_settings():
......
......@@ -113,7 +113,7 @@ def test_i_have_entered_a_new_course_start_date(step):
@step('The warning about course start date goes away$')
def test_the_warning_about_course_start_date_goes_away(step):
assert_equal(0, len(world.css_find('.message-error')))
assert world.is_css_not_present('.message-error')
assert_false('error' in world.css_find(COURSE_START_DATE_CSS).first._element.get_attribute('class'))
assert_false('error' in world.css_find(COURSE_START_TIME_CSS).first._element.get_attribute('class'))
......
......@@ -5,7 +5,7 @@ from lettuce import world, step
from common import create_studio_user
from django.contrib.auth.models import Group
from auth.authz import get_course_groupname_for_role, get_user_by_email
from nose.tools import assert_true # pylint: disable=E0611
from nose.tools import assert_true, assert_in # pylint: disable=E0611
PASSWORD = 'test'
EMAIL_EXTENSION = '@edx.org'
......@@ -112,12 +112,12 @@ def other_user_login(_step, name):
@step(u's?he does( not)? see the course on (his|her) page')
def see_course(_step, inverted, gender='self'):
class_css = 'h3.course-title'
all_courses = world.css_find(class_css, wait_time=1)
all_names = [item.html for item in all_courses]
if inverted:
assert not world.scenario_dict['COURSE'].display_name in all_names
assert world.is_css_not_present(class_css)
else:
assert world.scenario_dict['COURSE'].display_name in all_names
all_courses = world.css_find(class_css)
all_names = [item.html for item in all_courses]
assert_in(world.scenario_dict['COURSE'].display_name, all_names)
@step(u'"([^"]*)" should( not)? be marked as an admin')
......
......@@ -4,6 +4,7 @@
from lettuce import world, step
from selenium.webdriver.common.keys import Keys
from common import type_in_codemirror
from nose.tools import assert_in # pylint: disable=E0611
@step(u'I go to the course updates page')
......@@ -21,14 +22,17 @@ def add_update(_step, text):
change_text(text)
@step(u'I should( not)? see the update "([^"]*)"$')
def check_update(_step, doesnt_see_update, text):
@step(u'I should see the update "([^"]*)"$')
def check_update(_step, text):
update_css = 'div.update-contents'
update = world.css_find(update_css, wait_time=1)
if doesnt_see_update:
assert len(update) == 0 or not text in update.html
else:
assert text in update.html
update_html = world.css_find(update_css).html
assert_in(text, update_html)
@step(u'I should not see the update "([^"]*)"$')
def check_no_update(_step, text):
update_css = 'div.update-contents'
assert world.is_css_not_present(update_css)
@step(u'I modify the text to "([^"]*)"$')
......
......@@ -5,6 +5,7 @@ from lettuce import world, step
from common import *
from terrain.steps import reload_the_page
from selenium.common.exceptions import InvalidElementStateException
from nose.tools import assert_in, assert_not_in # pylint: disable=E0611
@step(u'I am viewing the grading settings')
......@@ -65,21 +66,25 @@ def change_assignment_name(step, old_name, new_name):
@step(u'I go back to the main course page')
def main_course_page(step):
main_page_link_css = 'a[href="/%s/%s/course/%s"]' % (world.scenario_dict['COURSE'].org,
world.scenario_dict['COURSE'].number,
world.scenario_dict['COURSE'].display_name.replace(' ', '_'),)
world.css_click(main_page_link_css)
main_page_link = '/{}/{}/course/{}'.format(world.scenario_dict['COURSE'].org,
world.scenario_dict['COURSE'].number,
world.scenario_dict['COURSE'].display_name.replace(' ', '_'),)
world.visit(main_page_link)
assert_in('Course Outline', world.css_text('h1.page-header'))
@step(u'I do( not)? see the assignment name "([^"]*)"$')
def see_assignment_name(step, do_not, name):
assignment_menu_css = 'ul.menu > li > a'
# First assert that it is there, make take a bit to redraw
assert world.css_find(assignment_menu_css)
assignment_menu = world.css_find(assignment_menu_css)
allnames = [item.html for item in assignment_menu]
if do_not:
assert not name in allnames
assert_not_in (name, allnames)
else:
assert name in allnames
assert_in (name, allnames)
@step(u'I delete the assignment type "([^"]*)"$')
......
......@@ -197,9 +197,15 @@ def high_level_source_in_editor(step):
def verify_high_level_source_links(step, visible):
assert_equal(visible, world.is_css_present('.launch-latex-compiler'))
if visible:
assert world.is_css_present('.launch-latex-compiler')
else:
assert world.is_css_not_present('.launch-latex-compiler')
world.cancel_component(step)
assert_equal(visible, world.is_css_present('.upload-button'))
if visible:
assert world.is_css_present('.upload-button')
else:
assert world.is_css_not_present('.upload-button')
def verify_modified_weight():
......
......@@ -12,7 +12,7 @@ def i_fill_in_the_registration_form(step):
register_form.find_by_name('password').fill('test')
register_form.find_by_name('username').fill('robot-studio')
register_form.find_by_name('name').fill('Robot Studio')
register_form.find_by_name('terms_of_service').check()
register_form.find_by_name('terms_of_service').click()
world.retry_on_exception(fill_in_reg_form)
......
......@@ -2,12 +2,11 @@
#pylint: disable=W0621
from lettuce import world, step
from selenium.webdriver.common.keys import Keys
from nose.tools import assert_true # pylint: disable=E0611
@step(u'I go to the static pages page')
def go_to_static(_step):
def go_to_static(step):
menu_css = 'li.nav-course-courseware'
static_css = 'li.nav-course-courseware-pages a'
world.css_click(menu_css)
......@@ -15,25 +14,37 @@ def go_to_static(_step):
@step(u'I add a new page')
def add_page(_step):
def add_page(step):
button_css = 'a.new-button'
world.css_click(button_css)
@step(u'I should( not)? see a "([^"]*)" static page$')
def see_page(_step, doesnt, page):
@step(u'I should not see a "([^"]*)" static page$')
def not_see_page(step, page):
# Either there are no pages, or there are pages but
# not the one I expect not to exist.
should_exist = not doesnt
# Since our only test for deletion right now deletes
# the only static page that existed, our success criteria
# will be that there are no static pages.
# In the future we can refactor if necessary.
tabs_css = 'li.component'
assert (world.is_css_not_present(tabs_css, wait_time=30))
@step(u'I should see a "([^"]*)" static page$')
def see_page(step, page):
# Need to retry here because the element
# will sometimes exist before the HTML content is loaded
exists_func = lambda(driver): page_exists(page) == should_exist
exists_func = lambda(driver): page_exists(page)
world.wait_for(exists_func)
assert_true(exists_func(None))
@step(u'I "([^"]*)" the "([^"]*)" page$')
def click_edit_delete(_step, edit_delete, page):
def click_edit_delete(step, edit_delete, page):
button_css = 'a.%s-button' % edit_delete
index = get_index(page)
assert index is not None
......@@ -41,7 +52,7 @@ def click_edit_delete(_step, edit_delete, page):
@step(u'I change the name to "([^"]*)"$')
def change_name(_step, new_name):
def change_name(step, new_name):
settings_css = '#settings-mode a'
world.css_click(settings_css)
input_css = 'input.setting-input'
......@@ -56,9 +67,10 @@ 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 world.css_html(page_name_css, index=i) == '\n {name}\n'.format(name=name):
if all_pages[i].html == '\n {name}\n'.format(name=name):
return i
return None
def page_exists(page):
return get_index(page) is not None
......@@ -7,6 +7,8 @@ import requests
import string
import random
import os
from nose.tools import assert_equal, assert_not_equal # pylint: disable=E0611
TEST_ROOT = settings.COMMON_TEST_DATA_ROOT
......@@ -32,7 +34,7 @@ def upload_file(_step, file_name):
@step(u'I upload the files (".*")$')
def upload_file(_step, files_string):
def upload_files(_step, files_string):
# Turn files_string to a list of file names
files = files_string.split(",")
files = map(lambda x: string.strip(x, ' "\''), files)
......@@ -48,19 +50,29 @@ def upload_file(_step, files_string):
world.css_click(close_css)
@step(u'I should( not)? see the file "([^"]*)" was uploaded$')
def check_upload(_step, do_not_see_file, file_name):
@step(u'I should not see the file "([^"]*)" was uploaded$')
def check_not_there(_step, file_name):
# Either there are no files, or there are files but
# not the one I expect not to exist.
# Since our only test for deletion right now deletes
# the only file that was uploaded, our success criteria
# will be that there are no files.
# In the future we can refactor if necessary.
names_css = 'td.name-col > a.filename'
assert(world.is_css_not_present(names_css))
@step(u'I should see the file "([^"]*)" was uploaded$')
def check_upload(_step, file_name):
index = get_index(file_name)
if do_not_see_file:
assert index == -1
else:
assert index != -1
assert_not_equal(index, -1)
@step(u'The url for the file "([^"]*)" is valid$')
def check_url(_step, file_name):
r = get_file(file_name)
assert r.status_code == 200
assert_equal(r.status_code , 200)
@step(u'I delete the file "([^"]*)"$')
......@@ -71,7 +83,7 @@ def delete_file(_step, file_name):
world.css_click(delete_css, index=index)
prompt_confirm_css = 'li.nav-item > a.action-primary'
world.css_click(prompt_confirm_css, success_condition=lambda: not world.css_visible(prompt_confirm_css))
world.css_click(prompt_confirm_css)
@step(u'I should see only one "([^"]*)"$')
......
......@@ -75,7 +75,8 @@ def make_desired_capabilities():
desired_capabilities['build'] = settings.SAUCE.get('BUILD')
desired_capabilities['video-upload-on-pass'] = False
desired_capabilities['sauce-advisor'] = False
desired_capabilities['record-screenshots'] = False
desired_capabilities['capture-html'] = True
desired_capabilities['record-screenshots'] = True
desired_capabilities['selenium-version'] = "2.34.0"
desired_capabilities['max-duration'] = 3600
desired_capabilities['public'] = 'public restricted'
......@@ -87,6 +88,7 @@ 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:
......
......@@ -82,11 +82,7 @@ def click_on_section(step, section):
subid = "ui-accordion-accordion-panel-" + str(int(section) - 1)
subsection_css = 'ul.ui-accordion-content-active[id=\'%s\'] > li > a' % subid
prev_url = world.browser.url
changed_section = lambda: prev_url != world.browser.url
#for some reason needed to do it in two steps
world.css_click(subsection_css, success_condition=changed_section)
world.css_click(subsection_css)
@step(u'I click on subsection "([^"]*)"$')
......
......@@ -129,7 +129,7 @@ Feature: Answer problems
When I press the button with the label "Hide Answer(s)"
Then the button with the label "Show Answer(s)" does appear
And I should not see "4.14159" anywhere on the page
Scenario: I can see my score on a problem when I answer it and after I reset it
Given I am viewing a "<ProblemType>" problem
When I answer a "<ProblemType>" problem "<Correctness>ly"
......
......@@ -101,6 +101,9 @@ def input_problem_answer(_, problem_type, correctness):
@step(u'I check a problem')
def check_problem(step):
# first scroll down so the loading mathjax button does not
# cover up the Check button
world.browser.execute_script("window.scrollTo(0,1024)")
world.css_click("input.check")
......
......@@ -23,9 +23,8 @@ def i_press_the_button_on_the_registration_form(step):
@step('I check the checkbox named "([^"]*)"$')
def i_check_checkbox(step, checkbox):
def check_box():
world.browser.find_by_name(checkbox).check()
world.retry_on_exception(check_box)
css_selector = 'input[name={}]'.format(checkbox)
world.css_check(css_selector)
@step('I should see "([^"]*)" in the dashboard banner$')
......
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