diff --git a/cms/djangoapps/contentstore/features/advanced-settings.feature b/cms/djangoapps/contentstore/features/advanced-settings.feature index 514eb8898e..a11a6cb869 100644 --- a/cms/djangoapps/contentstore/features/advanced-settings.feature +++ b/cms/djangoapps/contentstore/features/advanced-settings.feature @@ -40,6 +40,7 @@ Feature: Advanced (manual) course policy And I reload the page 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 Given I am on the Advanced Course Settings page in Studio When I create a non-JSON value not in quotes diff --git a/cms/djangoapps/contentstore/features/checklists.feature b/cms/djangoapps/contentstore/features/checklists.feature index 10db23c4fa..f13ce53fc2 100644 --- a/cms/djangoapps/contentstore/features/checklists.feature +++ b/cms/djangoapps/contentstore/features/checklists.feature @@ -10,6 +10,7 @@ Feature: Course checklists Then I can check and uncheck tasks in a checklist 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 Given I have opened Checklists When I select a link to the course outline @@ -17,6 +18,7 @@ Feature: Course checklists And I press the browser back button 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 Given I have opened Checklists When I select a link to help page diff --git a/cms/djangoapps/contentstore/features/common.py b/cms/djangoapps/contentstore/features/common.py index c39e074d90..69d2213eb4 100644 --- a/cms/djangoapps/contentstore/features/common.py +++ b/cms/djangoapps/contentstore/features/common.py @@ -70,8 +70,12 @@ def press_the_notification_button(_step, name): 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 - - world.css_click(css, success_condition=button_clicked), '%s button not clicked after 5 attempts.' % name + 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)) + else: + world.css_click(css, success_condition=button_clicked), '%s button not clicked after 5 attempts.' % name @step('I change the "(.*)" field to "(.*)"$') @@ -230,7 +234,7 @@ def i_created_video_alpha(step): def i_enabled_the_advanced_module(step, module): step.given('I have opened a new course section in Studio') 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) press_the_notification_button(step, 'Save') @@ -272,7 +276,7 @@ def i_am_shown_a_notification(step, notification_type): 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', '')") g = world.css_find("div.CodeMirror.CodeMirror-focused > div > textarea") if world.is_mac(): @@ -281,3 +285,5 @@ def type_in_codemirror(index, text): g._element.send_keys(Keys.CONTROL + 'a') g._element.send_keys(Keys.DELETE) g._element.send_keys(text) + if world.is_firefox(): + world.trigger_event('div.CodeMirror', index=index, event='blur') diff --git a/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py b/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py index 5db979bfa2..606e3dcee8 100644 --- a/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py +++ b/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py @@ -56,7 +56,7 @@ def click_component_from_menu(category, boilerplate, expected_css): def edit_component_and_select_settings(): world.wait_for(lambda _driver: world.css_visible('a.edit-button')) world.css_click('a.edit-button') - world.css_click('#settings-mode') + world.css_click('#settings-mode a') @world.absorb @@ -114,8 +114,20 @@ def revert_setting_entry(label): @world.absorb def get_setting_entry(label): - settings = world.browser.find_by_css('.wrapper-comp-setting') - for setting in settings: - if setting.find_by_css('.setting-label')[0].value == label: - return setting - return None + def get_setting(): + settings = world.css_find('.wrapper-comp-setting') + for setting in settings: + if setting.find_by_css('.setting-label')[0].value == label: + 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) diff --git a/cms/djangoapps/contentstore/features/course-team.feature b/cms/djangoapps/contentstore/features/course-team.feature index 20171eeae5..95843fc423 100644 --- a/cms/djangoapps/contentstore/features/course-team.feature +++ b/cms/djangoapps/contentstore/features/course-team.feature @@ -15,6 +15,8 @@ Feature: Course Team And I am viewing the course team settings When I add "bob" to the course team And "bob" logs in + And he selects the new course + And he views the course team settings Then he cannot delete users And he cannot add users diff --git a/cms/djangoapps/contentstore/features/course-team.py b/cms/djangoapps/contentstore/features/course-team.py index 2871d7a7af..07c30e1187 100644 --- a/cms/djangoapps/contentstore/features/course-team.py +++ b/cms/djangoapps/contentstore/features/course-team.py @@ -42,9 +42,9 @@ def add_other_user(_step, name): world.wait(0.5) email_css = 'input#user-email-input' - f = world.css_find(email_css) - f._element.send_keys(name, EMAIL_EXTENSION) - + world.css_fill(email_css, name + EMAIL_EXTENSION) + if world.is_firefox(): + world.trigger_event(email_css) confirm_css = 'form.create-user button.action-primary' world.css_click(confirm_css) diff --git a/cms/djangoapps/contentstore/features/course-updates.py b/cms/djangoapps/contentstore/features/course-updates.py index 9506191a76..f431af9cf5 100644 --- a/cms/djangoapps/contentstore/features/course-updates.py +++ b/cms/djangoapps/contentstore/features/course-updates.py @@ -9,7 +9,7 @@ from common import type_in_codemirror @step(u'I go to the course updates page') def go_to_updates(_step): 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(updates_css) diff --git a/cms/djangoapps/contentstore/features/problem-editor.feature b/cms/djangoapps/contentstore/features/problem-editor.feature index cc1d766d2e..50c49a1896 100644 --- a/cms/djangoapps/contentstore/features/problem-editor.feature +++ b/cms/djangoapps/contentstore/features/problem-editor.feature @@ -47,12 +47,12 @@ Feature: Problem Editor Scenario: User cannot type decimal values integer number field Given I have created a Blank Common Problem 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 Given I have created a Blank Common Problem 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 Given I have created a Blank Common Problem @@ -66,6 +66,7 @@ Feature: Problem Editor When I edit and select Settings 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) Given I have created a LaTeX Problem When I edit and compile the High Level Source diff --git a/cms/djangoapps/contentstore/features/problem-editor.py b/cms/djangoapps/contentstore/features/problem-editor.py index d7ccb557ba..d891789e4a 100644 --- a/cms/djangoapps/contentstore/features/problem-editor.py +++ b/cms/djangoapps/contentstore/features/problem-editor.py @@ -45,7 +45,10 @@ def i_see_five_settings_with_values(step): 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). - 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() @@ -57,7 +60,10 @@ 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): - 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() @@ -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) -@step('if I set the max attempts to "(.*)", it displays initially as "(.*)", and is persisted as "(.*)"') -def set_the_max_attempts(step, max_attempts_set, max_attempts_displayed, max_attempts_persisted): - world.get_setting_entry(MAXIMUM_ATTEMPTS).find_by_css('.setting-input')[0].fill(max_attempts_set) - world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, max_attempts_displayed, True) +@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 + 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.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') @@ -213,7 +223,11 @@ def verify_unset_display_name(): 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(): diff --git a/cms/djangoapps/contentstore/features/section.feature b/cms/djangoapps/contentstore/features/section.feature index d9dd6f9398..6402db1bcb 100644 --- a/cms/djangoapps/contentstore/features/section.feature +++ b/cms/djangoapps/contentstore/features/section.feature @@ -3,7 +3,6 @@ Feature: Create Section As a course author I want to create and edit sections - @skip Scenario: Add a new section to a course Given I have opened a new course in Studio When I click the New Section link diff --git a/cms/djangoapps/contentstore/features/static-pages.py b/cms/djangoapps/contentstore/features/static-pages.py index 3c9226f874..d3244955e1 100644 --- a/cms/djangoapps/contentstore/features/static-pages.py +++ b/cms/djangoapps/contentstore/features/static-pages.py @@ -8,7 +8,7 @@ from selenium.webdriver.common.keys import Keys @step(u'I go to the static pages page') def go_to_static(_step): 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(static_css) @@ -38,14 +38,12 @@ def click_edit_delete(_step, edit_delete, page): @step(u'I change the name to "([^"]*)"$') def change_name(_step, new_name): - settings_css = '#settings-mode' + settings_css = '#settings-mode a' world.css_click(settings_css) input_css = 'input.setting-input' - name_input = world.css_find(input_css) - old_name = name_input.value - for count in range(len(old_name)): - name_input._element.send_keys(Keys.END, Keys.BACK_SPACE) - name_input._element.send_keys(new_name) + world.css_fill(input_css, new_name) + if world.is_firefox(): + world.trigger_event(input_css) save_button = 'a.save-button' world.css_click(save_button) diff --git a/cms/djangoapps/contentstore/features/textbooks.py b/cms/djangoapps/contentstore/features/textbooks.py index ca135d9725..d9c08ec6eb 100644 --- a/cms/djangoapps/contentstore/features/textbooks.py +++ b/cms/djangoapps/contentstore/features/textbooks.py @@ -11,8 +11,8 @@ TEST_ROOT = settings.COMMON_TEST_DATA_ROOT @step(u'I go to the textbooks page') def go_to_uploads(_step): world.click_course_content() - menu_css = 'li.nav-course-courseware-textbooks' - world.css_find(menu_css).click() + menu_css = 'li.nav-course-courseware-textbooks a' + world.css_click(menu_css) @step(u'I should see a message telling me to create a new textbook') @@ -45,6 +45,8 @@ def click_new_textbook(_step, on): def name_textbook(_step, name): input_css = ".textbook input[name=textbook-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 "([^"]*)"') @@ -52,6 +54,8 @@ def name_chapter(_step, ordinal, name): index = ["first", "second", "third"].index(ordinal) input_css = ".textbook .chapter{i} input.chapter-name".format(i=index+1) 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') @@ -59,6 +63,8 @@ def asset_chapter(_step, name, ordinal): index = ["first", "second", "third"].index(ordinal) input_css = ".textbook .chapter{i} input.chapter-asset-path".format(i=index+1) 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') diff --git a/cms/djangoapps/contentstore/features/upload.py b/cms/djangoapps/contentstore/features/upload.py index acccdfe6ca..a989d6c07f 100644 --- a/cms/djangoapps/contentstore/features/upload.py +++ b/cms/djangoapps/contentstore/features/upload.py @@ -13,7 +13,7 @@ TEST_ROOT = settings.COMMON_TEST_DATA_ROOT @step(u'I go to the files and uploads page') def go_to_uploads(_step): 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(uploads_css) diff --git a/cms/djangoapps/contentstore/features/video.feature b/cms/djangoapps/contentstore/features/video.feature index d67a0b2f72..634bb8a17f 100644 --- a/cms/djangoapps/contentstore/features/video.feature +++ b/cms/djangoapps/contentstore/features/video.feature @@ -23,6 +23,7 @@ Feature: Video Component And I have toggled 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 Given I have created a Video Alpha component Then when I view the videoalpha it does not have autoplay enabled diff --git a/cms/djangoapps/contentstore/features/video.py b/cms/djangoapps/contentstore/features/video.py index 0f8b87171c..e27ca28eb7 100644 --- a/cms/djangoapps/contentstore/features/video.py +++ b/cms/djangoapps/contentstore/features/video.py @@ -33,7 +33,9 @@ def hide_or_show_captions(step, shown): # click the button rather than the tooltip, so move the mouse # away to make it disappear. 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) @step('I edit the component') diff --git a/common/djangoapps/terrain/ui_helpers.py b/common/djangoapps/terrain/ui_helpers.py index 2b81e9bd7f..3ab7e11b47 100644 --- a/common/djangoapps/terrain/ui_helpers.py +++ b/common/djangoapps/terrain/ui_helpers.py @@ -44,8 +44,8 @@ def is_css_not_present(css_selector, wait_time=5): @world.absorb -def css_has_text(css_selector, text): - return world.css_text(css_selector) == text +def css_has_text(css_selector, text, index=0, max_attempts=5): + return world.css_text(css_selector, index=index, max_attempts=max_attempts) == text @world.absorb @@ -235,6 +235,13 @@ def click_tools(): def is_mac(): 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 def retry_on_exception(func, max_attempts=5): diff --git a/lms/djangoapps/courseware/features/high-level-tabs.py b/lms/djangoapps/courseware/features/high-level-tabs.py index 056c627803..4e6ebb70dd 100644 --- a/lms/djangoapps/courseware/features/high-level-tabs.py +++ b/lms/djangoapps/courseware/features/high-level-tabs.py @@ -8,4 +8,5 @@ def i_click_on_the_tab_and_check(step): tab_text = tab_title['TabName'] title = tab_title['PageTitle'] world.click_link(tab_text) + world.wait_for(lambda _driver:title in world.browser.title) assert(title in world.browser.title) diff --git a/lms/djangoapps/courseware/features/login.feature b/lms/djangoapps/courseware/features/login.feature index b229533171..2b90c56f2d 100644 --- a/lms/djangoapps/courseware/features/login.feature +++ b/lms/djangoapps/courseware/features/login.feature @@ -11,6 +11,7 @@ Feature: Login in as a registered user And I submit my credentials on the login form 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 Given I am an edX user And I am an activated user diff --git a/lms/djangoapps/courseware/features/problems_setup.py b/lms/djangoapps/courseware/features/problems_setup.py index 67dfbf0dc5..2ddbbcdeb8 100644 --- a/lms/djangoapps/courseware/features/problems_setup.py +++ b/lms/djangoapps/courseware/features/problems_setup.py @@ -226,7 +226,6 @@ def answer_problem(problem_type, correctness): input_value = "8" if correctness == 'correct' else "5" choice = "choiceinput_0bc" if correctness == 'correct' else "choiceinput_1bc" - world.css_check(inputfield(problem_type, choice=choice)) world.css_fill( inputfield( problem_type, @@ -234,6 +233,7 @@ def answer_problem(problem_type, correctness): ), input_value ) + world.css_check(inputfield(problem_type, choice=choice)) def problem_has_answer(problem_type, answer_class): diff --git a/lms/djangoapps/courseware/features/signup.feature b/lms/djangoapps/courseware/features/signup.feature index cfc8b6e924..19dfd74f1c 100644 --- a/lms/djangoapps/courseware/features/signup.feature +++ b/lms/djangoapps/courseware/features/signup.feature @@ -3,6 +3,7 @@ Feature: Sign in As a new user I want to signup for a student account + # CHROME ONLY, firefox will not redirect properly Scenario: Sign up from the homepage Given I visit the homepage When I click the link with the text "Register Now" diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 659867a2f3..9179315797 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -81,7 +81,7 @@ nosexcover==1.0.7 pep8==1.4.5 pylint==0.28 rednose==0.3 -selenium==2.33.0 +selenium==2.34.0 splinter==0.5.4 django_nose==1.1 django-jasmine==0.3.2