Commit 02d8da1c by Jonah Stanley

Merge pull request #594 from edx/jonahstanley/firefox-acceptance-tests

Jonahstanley/firefox acceptance tests
parents 581a8a62 3e68bdaa
...@@ -40,6 +40,7 @@ Feature: Advanced (manual) course policy ...@@ -40,6 +40,7 @@ Feature: Advanced (manual) course policy
And I reload the page And I reload the page
Then the policy key value is unchanged Then the policy key value is unchanged
# This feature will work in Firefox only when Firefox is the active window
Scenario: Test automatic quoting of non-JSON values Scenario: Test automatic quoting of non-JSON values
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
When I create a non-JSON value not in quotes When I create a non-JSON value not in quotes
......
...@@ -10,6 +10,7 @@ Feature: Course checklists ...@@ -10,6 +10,7 @@ Feature: Course checklists
Then I can check and uncheck tasks in a checklist Then I can check and uncheck tasks in a checklist
And They are correctly selected after reloading the page And They are correctly selected after reloading the page
# CHROME ONLY, due to issues getting link to be active in firefox
Scenario: A task can link to a location within Studio Scenario: A task can link to a location within Studio
Given I have opened Checklists Given I have opened Checklists
When I select a link to the course outline When I select a link to the course outline
...@@ -17,6 +18,7 @@ Feature: Course checklists ...@@ -17,6 +18,7 @@ Feature: Course checklists
And I press the browser back button And I press the browser back button
Then I am brought back to the course outline in the correct state Then I am brought back to the course outline in the correct state
# CHROME ONLY, due to issues getting link to be active in firefox
Scenario: A task can link to a location outside Studio Scenario: A task can link to a location outside Studio
Given I have opened Checklists Given I have opened Checklists
When I select a link to help page When I select a link to help page
......
...@@ -70,8 +70,12 @@ def press_the_notification_button(_step, name): ...@@ -70,8 +70,12 @@ def press_the_notification_button(_step, name):
confirmation_dismissed = world.is_css_not_present('.is-shown.wrapper-notification-warning') confirmation_dismissed = world.is_css_not_present('.is-shown.wrapper-notification-warning')
error_showing = world.is_css_present('.is-shown.wrapper-notification-error') error_showing = world.is_css_present('.is-shown.wrapper-notification-error')
return confirmation_dismissed or error_showing return confirmation_dismissed or error_showing
if world.is_firefox():
world.css_click(css, success_condition=button_clicked), '%s button not clicked after 5 attempts.' % name # 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))
else:
world.css_click(css, success_condition=button_clicked), '%s button not clicked after 5 attempts.' % name
@step('I change the "(.*)" field to "(.*)"$') @step('I change the "(.*)" field to "(.*)"$')
...@@ -230,7 +234,7 @@ def i_created_video_alpha(step): ...@@ -230,7 +234,7 @@ def i_created_video_alpha(step):
def i_enabled_the_advanced_module(step, module): def i_enabled_the_advanced_module(step, module):
step.given('I have opened a new course section in Studio') step.given('I have opened a new course section in Studio')
world.css_click('.nav-course-settings') world.css_click('.nav-course-settings')
world.css_click('.nav-course-settings-advanced') world.css_click('.nav-course-settings-advanced a')
type_in_codemirror(0, '["%s"]' % module) type_in_codemirror(0, '["%s"]' % module)
press_the_notification_button(step, 'Save') press_the_notification_button(step, 'Save')
...@@ -272,7 +276,7 @@ def i_am_shown_a_notification(step, notification_type): ...@@ -272,7 +276,7 @@ def i_am_shown_a_notification(step, notification_type):
def type_in_codemirror(index, text): def type_in_codemirror(index, text):
world.css_click(".CodeMirror", index=index) world.css_click("div.CodeMirror-lines", index=index)
world.browser.execute_script("$('div.CodeMirror.CodeMirror-focused > div').css('overflow', '')") world.browser.execute_script("$('div.CodeMirror.CodeMirror-focused > div').css('overflow', '')")
g = world.css_find("div.CodeMirror.CodeMirror-focused > div > textarea") g = world.css_find("div.CodeMirror.CodeMirror-focused > div > textarea")
if world.is_mac(): if world.is_mac():
...@@ -281,3 +285,5 @@ def type_in_codemirror(index, text): ...@@ -281,3 +285,5 @@ def type_in_codemirror(index, text):
g._element.send_keys(Keys.CONTROL + 'a') g._element.send_keys(Keys.CONTROL + 'a')
g._element.send_keys(Keys.DELETE) g._element.send_keys(Keys.DELETE)
g._element.send_keys(text) g._element.send_keys(text)
if world.is_firefox():
world.trigger_event('div.CodeMirror', index=index, event='blur')
...@@ -56,7 +56,7 @@ def click_component_from_menu(category, boilerplate, expected_css): ...@@ -56,7 +56,7 @@ def click_component_from_menu(category, boilerplate, expected_css):
def edit_component_and_select_settings(): def edit_component_and_select_settings():
world.wait_for(lambda _driver: world.css_visible('a.edit-button')) world.wait_for(lambda _driver: world.css_visible('a.edit-button'))
world.css_click('a.edit-button') world.css_click('a.edit-button')
world.css_click('#settings-mode') world.css_click('#settings-mode a')
@world.absorb @world.absorb
...@@ -114,8 +114,20 @@ def revert_setting_entry(label): ...@@ -114,8 +114,20 @@ def revert_setting_entry(label):
@world.absorb @world.absorb
def get_setting_entry(label): def get_setting_entry(label):
settings = world.browser.find_by_css('.wrapper-comp-setting') def get_setting():
for setting in settings: settings = world.css_find('.wrapper-comp-setting')
if setting.find_by_css('.setting-label')[0].value == label: for setting in settings:
return setting if setting.find_by_css('.setting-label')[0].value == label:
return None return setting
return None
return world.retry_on_exception(get_setting)
@world.absorb
def get_setting_entry_index(label):
def get_index():
settings = world.css_find('.wrapper-comp-setting')
for index, setting in enumerate(settings):
if setting.find_by_css('.setting-label')[0].value == label:
return index
return None
return world.retry_on_exception(get_index)
...@@ -15,6 +15,8 @@ Feature: Course Team ...@@ -15,6 +15,8 @@ Feature: Course Team
And I am viewing the course team settings And I am viewing the course team settings
When I add "bob" to the course team When I add "bob" to the course team
And "bob" logs in And "bob" logs in
And he selects the new course
And he views the course team settings
Then he cannot delete users Then he cannot delete users
And he cannot add users And he cannot add users
......
...@@ -42,9 +42,9 @@ def add_other_user(_step, name): ...@@ -42,9 +42,9 @@ def add_other_user(_step, name):
world.wait(0.5) world.wait(0.5)
email_css = 'input#user-email-input' email_css = 'input#user-email-input'
f = world.css_find(email_css) world.css_fill(email_css, name + EMAIL_EXTENSION)
f._element.send_keys(name, EMAIL_EXTENSION) if world.is_firefox():
world.trigger_event(email_css)
confirm_css = 'form.create-user button.action-primary' confirm_css = 'form.create-user button.action-primary'
world.css_click(confirm_css) world.css_click(confirm_css)
......
...@@ -9,7 +9,7 @@ from common import type_in_codemirror ...@@ -9,7 +9,7 @@ from common import type_in_codemirror
@step(u'I go to the course updates page') @step(u'I go to the course updates page')
def go_to_updates(_step): def go_to_updates(_step):
menu_css = 'li.nav-course-courseware' menu_css = 'li.nav-course-courseware'
updates_css = 'li.nav-course-courseware-updates' updates_css = 'li.nav-course-courseware-updates a'
world.css_click(menu_css) world.css_click(menu_css)
world.css_click(updates_css) world.css_click(updates_css)
......
...@@ -47,12 +47,12 @@ Feature: Problem Editor ...@@ -47,12 +47,12 @@ Feature: Problem Editor
Scenario: User cannot type decimal values integer number field Scenario: User cannot type decimal values integer number field
Given I have created a Blank Common Problem Given I have created a Blank Common Problem
When I edit and select Settings When I edit and select Settings
Then if I set the max attempts to "2.34", it displays initially as "234", and is persisted as "234" Then if I set the max attempts to "2.34", it will persist as a valid integer
Scenario: User cannot type out of range values in an integer number field Scenario: User cannot type out of range values in an integer number field
Given I have created a Blank Common Problem Given I have created a Blank Common Problem
When I edit and select Settings When I edit and select Settings
Then if I set the max attempts to "-3", it displays initially as "-3", and is persisted as "0" Then if I set the max attempts to "-3", it will persist as a valid integer
Scenario: Settings changes are not saved on Cancel Scenario: Settings changes are not saved on Cancel
Given I have created a Blank Common Problem Given I have created a Blank Common Problem
...@@ -66,6 +66,7 @@ Feature: Problem Editor ...@@ -66,6 +66,7 @@ Feature: Problem Editor
When I edit and select Settings When I edit and select Settings
Then Edit High Level Source is visible Then Edit High Level Source is visible
# This feature will work in Firefox only when Firefox is the active window
Scenario: High Level source is persisted for LaTeX problem (bug STUD-280) Scenario: High Level source is persisted for LaTeX problem (bug STUD-280)
Given I have created a LaTeX Problem Given I have created a LaTeX Problem
When I edit and compile the High Level Source When I edit and compile the High Level Source
......
...@@ -45,7 +45,10 @@ def i_see_five_settings_with_values(step): ...@@ -45,7 +45,10 @@ def i_see_five_settings_with_values(step):
def i_can_modify_the_display_name(step): def i_can_modify_the_display_name(step):
# Verifying that the display name can be a string containing a floating point value # 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). # (to confirm that we don't throw an error because it is of the wrong type).
world.get_setting_entry(DISPLAY_NAME).find_by_css('.setting-input')[0].fill('3.4') 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)
verify_modified_display_name() verify_modified_display_name()
...@@ -57,7 +60,10 @@ def my_display_name_change_is_persisted_on_save(step): ...@@ -57,7 +60,10 @@ def my_display_name_change_is_persisted_on_save(step):
@step('I can specify special characters in the display name') @step('I can specify special characters in the display name')
def i_can_modify_the_display_name_with_special_chars(step): def i_can_modify_the_display_name_with_special_chars(step):
world.get_setting_entry(DISPLAY_NAME).find_by_css('.setting-input')[0].fill("updated ' \" &") 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)
verify_modified_display_name_with_special_chars() verify_modified_display_name_with_special_chars()
...@@ -127,12 +133,16 @@ def set_the_weight_to_abc(step, bad_weight): ...@@ -127,12 +133,16 @@ def set_the_weight_to_abc(step, bad_weight):
world.verify_setting_entry(world.get_setting_entry(PROBLEM_WEIGHT), PROBLEM_WEIGHT, "", False) world.verify_setting_entry(world.get_setting_entry(PROBLEM_WEIGHT), PROBLEM_WEIGHT, "", False)
@step('if I set the max attempts to "(.*)", it displays initially as "(.*)", and is persisted as "(.*)"') @step('if I set the max attempts to "(.*)", it will persist as a valid integer$')
def set_the_max_attempts(step, max_attempts_set, max_attempts_displayed, max_attempts_persisted): def set_the_max_attempts(step, max_attempts_set):
world.get_setting_entry(MAXIMUM_ATTEMPTS).find_by_css('.setting-input')[0].fill(max_attempts_set) # on firefox with selenium, the behaviour is different. eg 2.34 displays as 2.34 and is persisted as 2
world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, max_attempts_displayed, True) 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)
world.save_component_and_reopen(step) world.save_component_and_reopen(step)
world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, max_attempts_persisted, True) value = int(world.css_value('input.setting-input', index=index))
assert value >= 0
@step('Edit High Level Source is not visible') @step('Edit High Level Source is not visible')
...@@ -213,7 +223,11 @@ def verify_unset_display_name(): ...@@ -213,7 +223,11 @@ def verify_unset_display_name():
def set_weight(weight): def set_weight(weight):
world.get_setting_entry(PROBLEM_WEIGHT).find_by_css('.setting-input')[0].fill(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')
def open_high_level_source(): def open_high_level_source():
......
...@@ -3,7 +3,6 @@ Feature: Create Section ...@@ -3,7 +3,6 @@ Feature: Create Section
As a course author As a course author
I want to create and edit sections I want to create and edit sections
@skip
Scenario: Add a new section to a course Scenario: Add a new section to a course
Given I have opened a new course in Studio Given I have opened a new course in Studio
When I click the New Section link When I click the New Section link
......
...@@ -8,7 +8,7 @@ from selenium.webdriver.common.keys import Keys ...@@ -8,7 +8,7 @@ from selenium.webdriver.common.keys import Keys
@step(u'I go to the static pages page') @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' menu_css = 'li.nav-course-courseware'
static_css = 'li.nav-course-courseware-pages' static_css = 'li.nav-course-courseware-pages a'
world.css_click(menu_css) world.css_click(menu_css)
world.css_click(static_css) world.css_click(static_css)
...@@ -38,14 +38,12 @@ def click_edit_delete(_step, edit_delete, page): ...@@ -38,14 +38,12 @@ def click_edit_delete(_step, edit_delete, page):
@step(u'I change the name to "([^"]*)"$') @step(u'I change the name to "([^"]*)"$')
def change_name(_step, new_name): def change_name(_step, new_name):
settings_css = '#settings-mode' settings_css = '#settings-mode a'
world.css_click(settings_css) world.css_click(settings_css)
input_css = 'input.setting-input' input_css = 'input.setting-input'
name_input = world.css_find(input_css) world.css_fill(input_css, new_name)
old_name = name_input.value if world.is_firefox():
for count in range(len(old_name)): world.trigger_event(input_css)
name_input._element.send_keys(Keys.END, Keys.BACK_SPACE)
name_input._element.send_keys(new_name)
save_button = 'a.save-button' save_button = 'a.save-button'
world.css_click(save_button) world.css_click(save_button)
......
...@@ -11,8 +11,8 @@ TEST_ROOT = settings.COMMON_TEST_DATA_ROOT ...@@ -11,8 +11,8 @@ TEST_ROOT = settings.COMMON_TEST_DATA_ROOT
@step(u'I go to the textbooks page') @step(u'I go to the textbooks page')
def go_to_uploads(_step): def go_to_uploads(_step):
world.click_course_content() world.click_course_content()
menu_css = 'li.nav-course-courseware-textbooks' menu_css = 'li.nav-course-courseware-textbooks a'
world.css_find(menu_css).click() world.css_click(menu_css)
@step(u'I should see a message telling me to create a new textbook') @step(u'I should see a message telling me to create a new textbook')
...@@ -45,6 +45,8 @@ def click_new_textbook(_step, on): ...@@ -45,6 +45,8 @@ def click_new_textbook(_step, on):
def name_textbook(_step, name): def name_textbook(_step, name):
input_css = ".textbook input[name=textbook-name]" input_css = ".textbook input[name=textbook-name]"
world.css_fill(input_css, name) world.css_fill(input_css, name)
if world.is_firefox():
world.trigger_event(input_css)
@step(u'I name the (first|second|third) chapter "([^"]*)"') @step(u'I name the (first|second|third) chapter "([^"]*)"')
...@@ -52,6 +54,8 @@ def name_chapter(_step, ordinal, name): ...@@ -52,6 +54,8 @@ def name_chapter(_step, ordinal, name):
index = ["first", "second", "third"].index(ordinal) index = ["first", "second", "third"].index(ordinal)
input_css = ".textbook .chapter{i} input.chapter-name".format(i=index+1) input_css = ".textbook .chapter{i} input.chapter-name".format(i=index+1)
world.css_fill(input_css, name) world.css_fill(input_css, name)
if world.is_firefox():
world.trigger_event(input_css)
@step(u'I type in "([^"]*)" for the (first|second|third) chapter asset') @step(u'I type in "([^"]*)" for the (first|second|third) chapter asset')
...@@ -59,6 +63,8 @@ def asset_chapter(_step, name, ordinal): ...@@ -59,6 +63,8 @@ def asset_chapter(_step, name, ordinal):
index = ["first", "second", "third"].index(ordinal) index = ["first", "second", "third"].index(ordinal)
input_css = ".textbook .chapter{i} input.chapter-asset-path".format(i=index+1) input_css = ".textbook .chapter{i} input.chapter-asset-path".format(i=index+1)
world.css_fill(input_css, name) world.css_fill(input_css, name)
if world.is_firefox():
world.trigger_event(input_css)
@step(u'I click the Upload Asset link for the (first|second|third) chapter') @step(u'I click the Upload Asset link for the (first|second|third) chapter')
......
...@@ -13,7 +13,7 @@ TEST_ROOT = settings.COMMON_TEST_DATA_ROOT ...@@ -13,7 +13,7 @@ TEST_ROOT = settings.COMMON_TEST_DATA_ROOT
@step(u'I go to the files and uploads page') @step(u'I go to the files and uploads page')
def go_to_uploads(_step): def go_to_uploads(_step):
menu_css = 'li.nav-course-courseware' menu_css = 'li.nav-course-courseware'
uploads_css = 'li.nav-course-courseware-uploads' uploads_css = 'li.nav-course-courseware-uploads a'
world.css_click(menu_css) world.css_click(menu_css)
world.css_click(uploads_css) world.css_click(uploads_css)
......
...@@ -23,6 +23,7 @@ Feature: Video Component ...@@ -23,6 +23,7 @@ Feature: Video Component
And I have toggled captions And I have toggled captions
Then when I view the video it does show the captions Then when I view the video it does show the captions
# Video Alpha Features will work in Firefox only when Firefox is the active window
Scenario: Autoplay is disabled in Studio for Video Alpha Scenario: Autoplay is disabled in Studio for Video Alpha
Given I have created a Video Alpha component Given I have created a Video Alpha component
Then when I view the videoalpha it does not have autoplay enabled Then when I view the videoalpha it does not have autoplay enabled
......
...@@ -33,7 +33,9 @@ def hide_or_show_captions(step, shown): ...@@ -33,7 +33,9 @@ def hide_or_show_captions(step, shown):
# click the button rather than the tooltip, so move the mouse # click the button rather than the tooltip, so move the mouse
# away to make it disappear. # away to make it disappear.
button = world.css_find(button_css) button = world.css_find(button_css)
button.mouse_out() # mouse_out is not implemented on firefox with selenium
if not world.is_firefox:
button.mouse_out()
world.css_click(button_css) world.css_click(button_css)
@step('I edit the component') @step('I edit the component')
......
...@@ -44,8 +44,8 @@ def is_css_not_present(css_selector, wait_time=5): ...@@ -44,8 +44,8 @@ def is_css_not_present(css_selector, wait_time=5):
@world.absorb @world.absorb
def css_has_text(css_selector, text): def css_has_text(css_selector, text, index=0, max_attempts=5):
return world.css_text(css_selector) == text return world.css_text(css_selector, index=index, max_attempts=max_attempts) == text
@world.absorb @world.absorb
...@@ -235,6 +235,13 @@ def click_tools(): ...@@ -235,6 +235,13 @@ def click_tools():
def is_mac(): def is_mac():
return platform.mac_ver()[0] is not '' return platform.mac_ver()[0] is not ''
@world.absorb
def is_firefox():
return world.browser.driver_name is 'Firefox'
@world.absorb
def trigger_event(css_selector, event='change', index=0):
world.browser.execute_script("$('{}:eq({})').trigger('{}')".format(css_selector, index, event))
@world.absorb @world.absorb
def retry_on_exception(func, max_attempts=5): def retry_on_exception(func, max_attempts=5):
......
...@@ -8,4 +8,5 @@ def i_click_on_the_tab_and_check(step): ...@@ -8,4 +8,5 @@ def i_click_on_the_tab_and_check(step):
tab_text = tab_title['TabName'] tab_text = tab_title['TabName']
title = tab_title['PageTitle'] title = tab_title['PageTitle']
world.click_link(tab_text) world.click_link(tab_text)
world.wait_for(lambda _driver:title in world.browser.title)
assert(title in world.browser.title) assert(title in world.browser.title)
...@@ -11,6 +11,7 @@ Feature: Login in as a registered user ...@@ -11,6 +11,7 @@ Feature: Login in as a registered user
And I submit my credentials on the login form And I submit my credentials on the login form
Then I should see the login error message "This account has not been activated" Then I should see the login error message "This account has not been activated"
# CHROME ONLY, firefox will not redirect properly
Scenario: Login to an activated account Scenario: Login to an activated account
Given I am an edX user Given I am an edX user
And I am an activated user And I am an activated user
......
...@@ -226,7 +226,6 @@ def answer_problem(problem_type, correctness): ...@@ -226,7 +226,6 @@ def answer_problem(problem_type, correctness):
input_value = "8" if correctness == 'correct' else "5" input_value = "8" if correctness == 'correct' else "5"
choice = "choiceinput_0bc" if correctness == 'correct' else "choiceinput_1bc" choice = "choiceinput_0bc" if correctness == 'correct' else "choiceinput_1bc"
world.css_check(inputfield(problem_type, choice=choice))
world.css_fill( world.css_fill(
inputfield( inputfield(
problem_type, problem_type,
...@@ -234,6 +233,7 @@ def answer_problem(problem_type, correctness): ...@@ -234,6 +233,7 @@ def answer_problem(problem_type, correctness):
), ),
input_value input_value
) )
world.css_check(inputfield(problem_type, choice=choice))
def problem_has_answer(problem_type, answer_class): def problem_has_answer(problem_type, answer_class):
......
...@@ -3,6 +3,7 @@ Feature: Sign in ...@@ -3,6 +3,7 @@ Feature: Sign in
As a new user As a new user
I want to signup for a student account I want to signup for a student account
# CHROME ONLY, firefox will not redirect properly
Scenario: Sign up from the homepage Scenario: Sign up from the homepage
Given I visit the homepage Given I visit the homepage
When I click the link with the text "Register Now" When I click the link with the text "Register Now"
......
...@@ -81,7 +81,7 @@ nosexcover==1.0.7 ...@@ -81,7 +81,7 @@ nosexcover==1.0.7
pep8==1.4.5 pep8==1.4.5
pylint==0.28 pylint==0.28
rednose==0.3 rednose==0.3
selenium==2.33.0 selenium==2.34.0
splinter==0.5.4 splinter==0.5.4
django_nose==1.1 django_nose==1.1
django-jasmine==0.3.2 django-jasmine==0.3.2
......
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