def _click_advanced(): css = 'ul.problem-type-tabs a[href="#tab2"]' world.css_click(css) # Wait for the advanced tab items to be displayed tab2_css = 'div.ui-tabs-panel#tab2' world.wait_for_visible(tab2_css)
def press_the_notification_button(_step, name): # 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(btn_css, event='focus') world.browser.execute_script("$('{}').click()".format(btn_css)) else: world.css_click(btn_css)
def click_a_button(step, button): # pylint: disable=unused-argument if button == "Generate Grade Report": # Go to the data download section of the instructor dash go_to_section("data_download") # Click generate grade report button world.css_click('input[name="calculate-grades-csv"]') # Expect to see a message that grade report is being generated expected_msg = "Your grade report is being generated! You can view the status of the generation task in the 'Pending Instructor Tasks' section." world.wait_for_visible('#grade-request-response') assert_in( expected_msg, world.css_text('#grade-request-response'), msg="Could not find grade report generation success message." ) elif button == "Grading Configuration": # Go to the data download section of the instructor dash go_to_section("data_download") world.css_click('input[name="dump-gradeconf"]') elif button == "List enrolled students' profile information": # Go to the data download section of the instructor dash go_to_section("data_download") world.css_click('input[name="list-profiles"]') else: raise ValueError("Unrecognized button option " + button)
def find_student_profile_table(step): # pylint: disable=unused-argument # Find the grading configuration display world.wait_for_visible('#data-student-profiles-table') # Wait for the data table to be populated world.wait_for(lambda _: world.css_text('#data-student-profiles-table') not in [u'', u'Loading']) if world.role == 'instructor': expected_data = [ world.instructor.username, world.instructor.email, world.instructor.profile.name, world.instructor.profile.gender, world.instructor.profile.goals ] elif world.role == 'staff': expected_data = [ world.staff.username, world.staff.email, world.staff.profile.name, world.staff.profile.gender, world.staff.profile.goals ] for datum in expected_data: assert_in(datum, world.css_text('#data-student-profiles-table'))
def is_hidden_button(_step, button, state): selector = VIDEO_BUTTONS[button] if state == "hidden": world.wait_for_invisible(selector) assert_false(world.css_visible(selector), "Button {0} is invisible, but should be visible".format(button)) else: world.wait_for_visible(selector) assert_true(world.css_visible(selector), "Button {0} is visible, but should be invisible".format(button))
def set_captions_visibility_state(_step, captions_state): SELECTOR = '.closed .subtitles' world.wait_for_visible('.hide-subtitles') if captions_state == 'closed': if world.is_css_not_present(SELECTOR): world.css_find('.hide-subtitles').click() else: if world.is_css_present(SELECTOR): world.css_find('.hide-subtitles').click()
def set_captions_visibility_state(_step, captions_state): SELECTOR = ".closed .subtitles" world.wait_for_visible(".hide-subtitles") if captions_state == "closed": if not world.is_css_present(SELECTOR): world.css_find(".hide-subtitles").click() else: if world.is_css_present(SELECTOR): world.css_find(".hide-subtitles").click()
def perform_action_in_plugin(action): # Wait for the plugin window to open. world.wait_for_visible('.mce-window') # Trigger the action action() # Click OK world.css_click('.mce-primary')
def when_i_navigate_to_a_section(step): section_css = 'h3[tabindex="-1"]' world.css_click(section_css) subid = "ui-accordion-accordion-panel-1" world.wait_for_visible("#" + subid) subsection_css = "ul.ui-accordion-content-active[id='{}'] > li > a".format(subid) world.css_click(subsection_css)
def see_a_range_slider_with_proper_range(_step, left, width): left = int(left.strip()) width = int(width.strip()) world.wait_for_visible(".slider-range") world.wait(4) slider_range = world.browser.driver.find_element_by_css_selector(".slider-range") assert int(round(float(slider_range.value_of_css_property("left")[:-2]))) == left assert int(round(float(slider_range.value_of_css_property("width")[:-2]))) == width
def verify_report_is_generated(report_name_substring): # Need to reload the page to see the reports table updated reload_the_page(step) world.wait_for_visible("#report-downloads-table") # Find table and assert a .csv file is present quoted_id = http.urlquote(world.course_key).replace("/", "_") expected_file_regexp = quoted_id + "_" + report_name_substring + "_\d{4}-\d{2}-\d{2}-\d{4}\.csv" assert_regexp_matches( world.css_html("#report-downloads-table"), expected_file_regexp, msg="Expected report filename was not found." )
def find_grade_report_csv_link(step): # pylint: disable=unused-argument # Need to reload the page to see the grades download table reload_the_page(step) world.wait_for_visible('#report-downloads-table') # Find table and assert a .csv file is present expected_file_regexp = 'edx_999_Test_Course_grade_report_\d{4}-\d{2}-\d{2}-\d{4}\.csv' assert_regexp_matches( world.css_html('#report-downloads-table'), expected_file_regexp, msg="Expected grade report filename was not found." )
def check_visibility(self, step, visible): r'the conditional contents are (?P<visible>\w+)$' world.wait_for_ajax_complete() assert_in(visible, ('visible', 'hidden')) if visible == 'visible': world.wait_for_visible('.hidden-contents') assert_true(world.css_visible('.hidden-contents')) else: assert_true(world.is_css_not_present('.hidden-contents'))
def find_grade_report_csv_link(step): # pylint: disable=unused-argument # Need to reload the page to see the grades download table reload_the_page(step) world.wait_for_visible('#report-downloads-table') # Find table and assert a .csv file is present quoted_id = http.urlquote(world.course_key).replace('/', '_') expected_file_regexp = quoted_id + '_grade_report_\d{4}-\d{2}-\d{2}-\d{4}\.csv' assert_regexp_matches( world.css_html('#report-downloads-table'), expected_file_regexp, msg="Expected grade report filename was not found." )
def check_visibility(self, step, visible): r"the conditional contents are (?P<visible>\w+)$" world.wait_for_ajax_complete() assert_in(visible, ("visible", "hidden")) if visible == "visible": world.wait_for_visible(".hidden-contents") assert_true(world.css_visible(".hidden-contents")) else: assert_true(world.is_css_not_present(".hidden-contents"))
def i_created_a_video_component(step): step.given("I am in Studio editing a new unit") world.create_component_instance(step=step, category="video") world.wait_for_xmodule() world.disable_jquery_animations() world.wait_for_present(".is-initialized") world.wait(DELAY) world.wait_for_invisible(SELECTORS["spinner"]) if not world.youtube.config.get("youtube_api_blocked"): world.wait_for_visible(SELECTORS["controls"])
def check_visibility(self, step, visible): r'the conditional contents are (?P<visible>\w+)$' world.wait_for_ajax_complete() assert_in(visible, ('visible', 'hidden')) if visible == 'visible': world.wait_for_visible('.hidden-contents') assert_true(world.css_visible('.hidden-contents')) else: assert_true(world.is_css_not_present('.hidden-contents')) assert_true(world.css_contains_text('.conditional-message', 'must be attempted before this will become visible.')) # sarina
def then_i_see_a_tables_of_modules_progress(step): world.wait_for_visible('.progress-report-list') if world.role == 'instructor': summary_text = "Test Course\nenrollments 1\nactive_students 1" elif world.role == 'staff': summary_text = "Test Course\nenrollments 2\nactive_students 2" modules_text = "i4x://edx/999/problem/Problem_1\ncorrect_map {u'i4x-org-cn-problem-unitid_2_1': 1}\ncount 2\ncourse_id edx/999/Test_Course\n" assert_true(world.browser.status_code.is_success()) assert_in(summary_text, world.css_text("table.summary-table")) assert_in(modules_text, world.css_text("table.modules-table"))
def click_grade(_step, version): version_map = { '1': {'selector': 'submit-button', 'expected_text': 'LTI consumer (edX) responded with XML content'}, '2': {'selector': 'submit-lti2-button', 'expected_text': 'LTI consumer (edX) responded with HTTP 200'}, } assert_in(version, version_map) location = world.scenario_dict['LTI'].location.html_id() iframe_name = 'ltiFrame-' + location with world.browser.get_iframe(iframe_name) as iframe: css_ele = version_map[version]['selector'] css_loc = '#' + css_ele world.wait_for_visible(css_loc) world.css_click(css_loc) assert iframe.is_text_present(version_map[version]['expected_text'])
def select_language(_step, code): selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format( code=code ) world.wait_for_present(selector) world.css_find(VIDEO_BUTTONS["CC"])[0].mouse_over() world.wait_for_visible(selector) world.css_click(selector) assert world.css_has_class(selector, 'active') assert len(world.css_find(VIDEO_MENUS["language"] + ' li.active')) == 1 assert world.css_visible('.subtitles') world.wait_for_ajax_complete()
def i_select_advanced_settings(step): world.click_course_settings() # The click handlers are set up so that if you click <body> # the menu disappears. This means that if we're even a *little* # bit off on the last item ('Advanced Settings'), the menu # will close and the test will fail. # For this reason, we retrieve the link and visit it directly # This is what the browser *should* be doing, since it's just a native # link with no JavaScript involved. link_css = 'li.nav-course-settings-advanced a' world.wait_for_visible(link_css) link = world.css_find(link_css).first['href'] world.visit(link)
def i_created_a_video_component(step): step.given('I am in Studio editing a new unit') world.create_component_instance( step=step, category='video', ) world.wait_for_xmodule() world.disable_jquery_animations() world.wait_for_present('.is-initialized') world.wait(DELAY) world.wait_for_invisible(SELECTORS['spinner']) if not world.youtube.config.get('youtube_api_blocked'): world.wait_for_visible(SELECTORS['controls'])
def confirm_the_prompt(step): 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)
def add_a_single_step_component(step): world.wait_for_xmodule() for step_hash in step.hashes: component = step_hash['Component'] assert_in(component, ['Discussion', 'Video']) css_selector = 'a[data-type="{}"]'.format(component.lower()) world.css_click(css_selector) # In the current implementation, all the "new component" # buttons are handled by one BackBone.js view. # If we click two buttons at super-human speed, # the view will miss the second click while it's # processing the first. # To account for this, we wait for each component # to be created before clicking the next component. world.wait_for_visible('section.xmodule_{}Module'.format(component))
def try_click(): problem_html_loc = section_loc.course_key.make_usage_key('problem', 'image').html_id() image_selector = "#imageinput_{}_2_1".format(problem_html_loc) input_selector = "#input_{}_2_1".format(problem_html_loc) world.browser.execute_script('$("body").on("click", function(event) {console.log(event);})') # pylint: disable=unicode-format-string initial_input = world.css_value(input_selector) world.wait_for_visible(image_selector) image = world.css_find(image_selector).first (image.action_chains .move_to_element(image._element) .move_by_offset(offset, offset) .click() .perform()) world.wait_for(lambda _: world.css_value(input_selector) != initial_input)
def try_click(): image_selector = "#imageinput_i4x-{0.org}-{0.course}-problem-image_2_1".format(section_loc) input_selector = "#input_i4x-{0.org}-{0.course}-problem-image_2_1".format(section_loc) world.browser.execute_script('$("body").on("click", function(event) {console.log(event);})') initial_input = world.css_value(input_selector) world.wait_for_visible(image_selector) image = world.css_find(image_selector).first (image.action_chains .move_to_element(image._element) .move_by_offset(offset, offset) .click() .perform()) world.wait_for(lambda _: world.css_value(input_selector) != initial_input)
def when_i_send_an_email(step, recipient): # Check that the recipient is valid assert_in( recipient, SEND_TO_OPTIONS, msg="Invalid recipient: {}".format(recipient) ) # Clear the queue of existing emails while not mail.queue.empty(): # pylint: disable=E1101 mail.queue.get() # pylint: disable=E1101 # Because we flush the database before each run, # we need to ensure that the email template fixture # is re-loaded into the database call_command('loaddata', 'course_email_template.json') # Go to the email section of the instructor dash world.visit('/courses/edx/999/Test_Course') world.css_click('a[href="/courses/edx/999/Test_Course/instructor"]') world.css_click('div.beta-button-wrapper>a') world.css_click('a[data-section="send_email"]') # Select the recipient world.select_option('send_to', SEND_TO_OPTIONS[recipient]) # Enter subject and message world.css_fill('input#id_subject', 'Hello') with world.browser.get_iframe('mce_0_ifr') as iframe: editor = iframe.find_by_id('tinymce')[0] editor.fill('test message') # Click send world.css_click('input[name="send"]') # Confirm the alert world.browser.get_alert().accept() # Expect to see a message that the email was sent expected_msg = "Your email was successfully queued for sending." world.wait_for_visible('#request-response') assert_in( expected_msg, world.css_text('#request-response'), msg="Could not find email success message." )
def select_language(_step, code): # Make sure that all ajax requests that affects the language menu are finished. # For example, request to get new translation etc. world.wait_for_ajax_complete() selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format(code=code) world.css_find(VIDEO_BUTTONS["CC"])[0].mouse_over() world.wait_for_present(".lang.open") world.css_click(selector) assert world.css_has_class(selector, "is-active") assert len(world.css_find(VIDEO_MENUS["language"] + " li.is-active")) == 1 # Make sure that all ajax requests that affects the display of captions are finished. # For example, request to get new translation etc. world.wait_for_ajax_complete() world.wait_for_visible(".subtitles") world.wait_for_present(".video.is-captions-rendered")
def i_created_a_video_component(_step): assert_less(world.youtube.config['youtube_api_response'].status_code, 400, "Real Youtube server is unavailable") world.create_course_with_unit() world.create_component_instance( step=_step, category='video', ) world.wait_for_xmodule() world.disable_jquery_animations() world.wait_for_present('.is-initialized') world.wait(DELAY) world.wait_for_invisible(SELECTORS['spinner']) if not world.youtube.config.get('youtube_api_blocked'): world.wait_for_visible(SELECTORS['controls'])
def move_slider(self, step): r'I move the slider to the right$' handle_selector = '.gst-input .ui-slider-handle' world.wait_for_visible(handle_selector) world.wait_for_visible('.gst-value #value-display') def try_move(): handle = world.css_find(handle_selector).first slider = world.css_find('.gst-input .ui-slider').first (handle.action_chains .click_and_hold(handle._element) .move_by_offset( int(handle._element.location['x'] + 400), 0 ).release().perform()) world.retry_on_exception(try_move)
def click_a_button(step, button): # pylint: disable=unused-argument if button == "Generate Grade Report": # Go to the data download section of the instructor dash go_to_section("data_download") # Click generate grade report button world.css_click('input[name="calculate-grades-csv"]') # Expect to see a message that grade report is being generated expected_msg = "Your grade report is being generated! You can view the status of the generation task in the 'Pending Instructor Tasks' section." world.wait_for_visible('#report-request-response') assert_in( expected_msg, world.css_text('#report-request-response'), msg="Could not find grade report generation success message.") elif button == "Grading Configuration": # Go to the data download section of the instructor dash go_to_section("data_download") world.css_click('input[name="dump-gradeconf"]') elif button == "List enrolled students' profile information": # Go to the data download section of the instructor dash go_to_section("data_download") world.css_click('input[name="list-profiles"]') elif button == "Download profile information as a CSV": # Go to the data download section of the instructor dash go_to_section("data_download") world.css_click('input[name="list-profiles-csv"]') else: raise ValueError("Unrecognized button option " + button)
def i_select_advanced_settings(step): world.wait_for_js_to_load() # pylint: disable=no-member world.wait_for_js_variable_truthy('window.studioNavMenuActive') # pylint: disable=no-member for _ in range(5): world.click_course_settings() # pylint: disable=no-member # The click handlers are set up so that if you click <body> # the menu disappears. This means that if we're even a *little* # bit off on the last item ('Advanced Settings'), the menu # will close and the test will fail. # For this reason, we retrieve the link and visit it directly # This is what the browser *should* be doing, since it's just a native # link with no JavaScript involved. link_css = 'li.nav-course-settings-advanced a' try: world.wait_for_visible(link_css) # pylint: disable=no-member break except AssertionError: continue link = world.css_find(link_css).first['href'] world.visit(link)
def view_staff_debug_info(step): css_selector = "a.instructor-info-action" world.css_click(css_selector) world.wait_for_visible("section.staff-modal")
def see_a_range_slider_with_proper_range(_step): world.wait_for_visible(VIDEO_BUTTONS['pause']) assert world.css_visible(".slider-range")
def check_feedback(self, step): r"""I receive feedback on that annotation problem$""" world.wait_for_visible(self.active_problem_selector('.tag-status.correct')) assert_equals(len(world.css_find(self.active_problem_selector('.tag-status.correct'))), 1) assert_equals(len(world.css_find(self.active_problem_selector('.show'))), 1)
def verify_cheat_sheet_displaying(_step): world.css_click("a.cheatsheet-toggle") css_selector = 'article.simple-editor-cheatsheet' world.wait_for_visible(css_selector)
def then_i_generate_csv_to_mongodb(step): world.wait_for_visible('.progress-report-list') world.css_click('input[name="generate-pgreport-csv"]') assert_true(world.browser.status_code.is_success())
def then_i_download_csv_from_mongodb(step): world.wait_for_visible('.progress-report-list') world.css_click('input[name="download-pgreport-csv"]') assert_true(world.browser.status_code.is_success())
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": if correctness == 'correct': world.css_check(inputfield('multiple choice', choice='choice_2')) else: world.css_check(inputfield('multiple choice', choice='choice_1')) elif problem_type == "checkbox": if correctness == 'correct': world.css_check(inputfield('checkbox', choice='choice_0')) world.css_check(inputfield('checkbox', choice='choice_2')) else: world.css_check(inputfield('checkbox', choice='choice_3')) elif problem_type == 'radio': if correctness == 'correct': world.css_check(inputfield('radio', choice='choice_2')) else: world.css_check(inputfield('radio', choice='choice_1')) elif problem_type == 'string': textvalue = 'correct string' if correctness == 'correct' else 'incorrect' world.css_fill(inputfield('string'), textvalue) elif problem_type == 'numerical': textvalue = "pi + 1" if correctness == 'correct' else str( random.randint(-2, 2)) world.css_fill(inputfield('numerical'), textvalue) elif problem_type == 'formula': textvalue = "x^2+2*x+y" if correctness == 'correct' else 'x^2' world.css_fill(inputfield('formula'), textvalue) elif problem_type == 'script': # Correct answer is any two integers that sum to 10 first_addend = random.randint(-100, 100) second_addend = 10 - first_addend # If we want an incorrect answer, then change # the second addend so they no longer sum to 10 if correctness == 'incorrect': second_addend += random.randint(1, 10) world.css_fill(inputfield('script', input_num=1), str(first_addend)) world.css_fill(inputfield('script', input_num=2), str(second_addend)) elif problem_type == 'code': # The fake xqueue server is configured to respond # correct / incorrect no matter what we submit. # Furthermore, since the inline code response uses # JavaScript to make the code display nicely, it's difficult # to programatically input text # (there's not <textarea> we can just fill text into) # For this reason, we submit the initial code in the response # (configured in the problem XML above) pass elif problem_type == 'radio_text' or problem_type == 'checkbox_text': input_value = "8" if correctness == 'correct' else "5" choice = "choiceinput_0bc" if correctness == 'correct' else "choiceinput_1bc" world.css_fill( inputfield(problem_type, choice="choiceinput_0_numtolerance_input_0"), input_value) world.css_check(inputfield(problem_type, choice=choice))
def i_see_reply_to_annotation_link(_step): css_selector = 'a.annotatable-reply' world.wait_for_visible(css_selector)
def add_update(_step, text): update_css = '.new-update-button' world.css_click(update_css) world.wait_for_visible('.CodeMirror') change_text(text)
def go_to_updates(_step): menu_css = 'li.nav-course-courseware' updates_css = 'li.nav-course-courseware-updates a' world.css_click(menu_css) world.css_click(updates_css) world.wait_for_visible('#course-handouts-view')
def change_video_speed(speed): world.browser.execute_script("$('.speeds').addClass('is-opened')") speed_css = 'li[data-speed="{0}"] a'.format(speed) world.wait_for_visible('.speeds') world.css_click(speed_css)
def controls_appear(_step): world.wait_for_visible('.video-controls')