From 17f54fbaff261a3692562def159cccb3392710f6 Mon Sep 17 00:00:00 2001 From: Jeremy Bowman Date: Tue, 7 Aug 2018 14:24:53 -0400 Subject: [PATCH] TE-2525 Finish removing nose.tools usage --- .../contentstore/features/common.py | 25 ++++----- .../contentstore/features/component.py | 5 +- .../component_settings_editor_helpers.py | 7 +-- .../contentstore/features/course-settings.py | 38 ++++++------- .../contentstore/features/grading.py | 43 +++++++-------- .../contentstore/features/html-editor.py | 53 ++++++++++--------- cms/djangoapps/contentstore/features/pages.py | 2 +- .../contentstore/features/problem-editor.py | 22 ++++---- .../contentstore/features/signup.py | 23 ++++---- common/djangoapps/terrain/steps.py | 3 +- common/djangoapps/terrain/ui_helpers.py | 3 +- lms/djangoapps/courseware/features/common.py | 5 +- lms/djangoapps/courseware/features/events.py | 15 +++--- lms/djangoapps/courseware/features/lti.py | 4 +- lms/djangoapps/instructor/features/common.py | 5 +- .../instructor/features/data_download.py | 4 +- openedx/core/lib/tests/tools.py | 43 +++++++++++++++ 17 files changed, 178 insertions(+), 122 deletions(-) create mode 100644 openedx/core/lib/tests/tools.py diff --git a/cms/djangoapps/contentstore/features/common.py b/cms/djangoapps/contentstore/features/common.py index 686c8ec156..ea8e98dfe6 100644 --- a/cms/djangoapps/contentstore/features/common.py +++ b/cms/djangoapps/contentstore/features/common.py @@ -1,4 +1,5 @@ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name import os @@ -6,9 +7,9 @@ from logging import getLogger from django.conf import settings from lettuce import step, world -from nose.tools import assert_in, assert_true from selenium.webdriver.common.keys import Keys +from openedx.core.lib.tests.tools import assert_in # pylint: disable=no-name-in-module from student import auth from student.models import get_user from student.roles import CourseInstructorRole, CourseStaffRole, GlobalStaff @@ -78,7 +79,7 @@ def i_have_populated_a_new_course(_step): @step('(I select|s?he selects) the new course') -def select_new_course(_step, whom): +def select_new_course(_step, _whom): course_link_css = 'a.course-link' world.css_click(course_link_css) @@ -103,7 +104,7 @@ def i_change_field_to_value(_step, field, value): field_css = '#%s' % '-'.join([s.lower() for s in field.split()]) ele = world.css_find(field_css).first ele.fill(value) - ele._element.send_keys(Keys.ENTER) + ele._element.send_keys(Keys.ENTER) # pylint: disable=protected-access @step('I reset the database') @@ -121,7 +122,7 @@ def reset_the_db(_step): @step('I see a confirmation that my changes have been saved') -def i_see_a_confirmation(step): +def i_see_a_confirmation(_step): confirmation_css = '#alert-confirmation' assert world.is_css_present(confirmation_css) @@ -199,12 +200,12 @@ def create_a_course(): course_link_css = 'a.course-link' world.css_click(course_link_css) course_title_css = 'span.course-title' - assert_true(world.is_css_present(course_title_css)) + assert world.is_css_present(course_title_css) def add_section(): world.css_click('.outline .button-new') - assert_true(world.is_css_present('.outline-section .xblock-field-value')) + assert world.is_css_present('.outline-section .xblock-field-value') def set_date_and_time(date_css, desired_date, time_css, desired_time, key=None): @@ -268,14 +269,14 @@ def edit_new_unit(step): @step('the save notification button is disabled') -def save_button_disabled(step): +def save_button_disabled(_step): button_css = '.action-save' disabled = 'is-disabled' assert world.css_has_class(button_css, disabled) @step('the "([^"]*)" button is disabled') -def button_disabled(step, value): +def button_disabled(_step, value): button_css = 'input[value="%s"]' % value assert world.css_has_class(button_css, 'is-disabled') @@ -312,12 +313,12 @@ def confirm_studio_prompt(): @step('I confirm the prompt') -def confirm_the_prompt(step): +def confirm_the_prompt(_step): confirm_studio_prompt() @step(u'I am shown a prompt$') -def i_am_shown_a_notification(step): +def i_am_shown_a_notification(_step): assert world.is_css_present('.wrapper-prompt') @@ -342,7 +343,7 @@ def get_codemirror_value(index=0, find_prefix="$"): def attach_file(filename, sub_path): path = os.path.join(TEST_ROOT, sub_path, filename) world.browser.execute_script("$('input.file-input').css('display', 'block')") - assert_true(os.path.exists(path)) + assert os.path.exists(path) world.browser.attach_file('file', os.path.abspath(path)) @@ -377,7 +378,7 @@ def other_user_login(step, name): login_form.find_by_name('password').fill("test") login_form.find_by_name('submit').click() world.retry_on_exception(fill_login_form) - assert_true(world.is_css_present('.new-course-button')) + assert world.is_css_present('.new-course-button') world.scenario_dict['USER'] = get_user(name + '@edx.org') diff --git a/cms/djangoapps/contentstore/features/component.py b/cms/djangoapps/contentstore/features/component.py index a884f08fa0..ef7c6fcee8 100644 --- a/cms/djangoapps/contentstore/features/component.py +++ b/cms/djangoapps/contentstore/features/component.py @@ -1,4 +1,5 @@ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name # Lettuce formats proposed definitions for unimplemented steps with the @@ -6,7 +7,7 @@ # pylint: disable=unused-argument from lettuce import step, world -from nose.tools import assert_equal, assert_in, assert_true +from openedx.core.lib.tests.tools import assert_equal, assert_in, assert_true # pylint: disable=no-name-in-module DISPLAY_NAME = "Display Name" @@ -110,7 +111,7 @@ def delete_components(step, number): # Pressing the button via css was not working reliably for the last component # when run in Chrome. - if world.browser.driver_name is 'Chrome': + if world.browser.driver_name == 'Chrome': world.browser.execute_script("$('{}').click()".format(btn_css)) else: world.css_click(btn_css) diff --git a/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py b/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py index a8474d70e6..f77b59abe6 100644 --- a/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py +++ b/cms/djangoapps/contentstore/features/component_settings_editor_helpers.py @@ -1,11 +1,12 @@ # disable missing docstring # pylint: disable=missing-docstring +# pylint: disable=no-member from lettuce import world -from nose.tools import assert_equal, assert_in from selenium.webdriver.common.keys import Keys from common import type_in_codemirror +from openedx.core.lib.tests.tools import assert_equal, assert_in # pylint: disable=no-name-in-module from terrain.steps import reload_the_page @@ -121,7 +122,7 @@ def edit_component_and_select_settings(): def ensure_settings_visible(): # Select the 'settings' tab if there is one (it isn't displayed if it is the only option) settings_button = world.browser.find_by_css('.settings-button') - if len(settings_button) > 0: + if settings_button: world.css_click('.settings-button') @@ -146,7 +147,7 @@ def select_editor_tab(tab_name): world.wait_for_ajax_complete() -def enter_xml_in_advanced_problem(step, text): +def enter_xml_in_advanced_problem(_step, text): """ Edits an advanced problem (assumes only on page), types the provided XML, and saves the component. diff --git a/cms/djangoapps/contentstore/features/course-settings.py b/cms/djangoapps/contentstore/features/course-settings.py index 9df6a5f091..54fb036ef6 100644 --- a/cms/djangoapps/contentstore/features/course-settings.py +++ b/cms/djangoapps/contentstore/features/course-settings.py @@ -1,9 +1,9 @@ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name from django.conf import settings from lettuce import step, world -from nose.tools import assert_false, assert_true from selenium.webdriver.common.keys import Keys from cms.djangoapps.contentstore.features.common import type_in_codemirror @@ -26,7 +26,7 @@ DEFAULT_TIME = "00:00" ############### ACTIONS #################### @step('I select Schedule and Details$') -def test_i_select_schedule_and_details(step): +def test_i_select_schedule_and_details(_step): world.click_course_settings() link_css = 'li.nav-course-settings-schedule a' world.css_click(link_css) @@ -43,7 +43,7 @@ def test_i_have_set_course_dates(step): @step('And I set course dates$') -def test_and_i_set_course_dates(step): +def test_and_i_set_course_dates(_step): set_date_or_time(COURSE_START_DATE_CSS, '12/20/2013') set_date_or_time(COURSE_END_DATE_CSS, '12/26/2013') set_date_or_time(ENROLLMENT_START_DATE_CSS, '12/1/2013') @@ -54,14 +54,14 @@ def test_and_i_set_course_dates(step): @step('And I clear all the dates except start$') -def test_and_i_clear_all_the_dates_except_start(step): +def test_and_i_clear_all_the_dates_except_start(_step): set_date_or_time(COURSE_END_DATE_CSS, '') set_date_or_time(ENROLLMENT_START_DATE_CSS, '') set_date_or_time(ENROLLMENT_END_DATE_CSS, '') @step('Then I see cleared dates$') -def test_then_i_see_cleared_dates(step): +def test_then_i_see_cleared_dates(_step): verify_date_or_time(COURSE_END_DATE_CSS, '') verify_date_or_time(ENROLLMENT_START_DATE_CSS, '') verify_date_or_time(ENROLLMENT_END_DATE_CSS, '') @@ -76,19 +76,19 @@ def test_then_i_see_cleared_dates(step): @step('I clear the course start date$') -def test_i_clear_the_course_start_date(step): +def test_i_clear_the_course_start_date(_step): set_date_or_time(COURSE_START_DATE_CSS, '') @step('I receive a warning about course start date$') -def test_i_receive_a_warning_about_course_start_date(step): - assert_true(world.css_has_text('.message-error', 'The course must have an assigned start date.')) - assert_true('error' in world.css_find(COURSE_START_DATE_CSS).first._element.get_attribute('class')) - assert_true('error' in world.css_find(COURSE_START_TIME_CSS).first._element.get_attribute('class')) +def test_i_receive_a_warning_about_course_start_date(_step): + assert world.css_has_text('.message-error', 'The course must have an assigned start date.') + assert 'error' in world.css_find(COURSE_START_DATE_CSS).first._element.get_attribute('class') # pylint: disable=protected-access + assert 'error' in world.css_find(COURSE_START_TIME_CSS).first._element.get_attribute('class') # pylint: disable=protected-access @step('the previously set start date is shown$') -def test_the_previously_set_start_date_is_shown(step): +def test_the_previously_set_start_date_is_shown(_step): verify_date_or_time(COURSE_START_DATE_CSS, '12/20/2013') verify_date_or_time(COURSE_START_TIME_CSS, DUMMY_TIME) @@ -101,26 +101,26 @@ def test_i_have_tried_to_clear_the_course_start(step): @step('I have entered a new course start date$') -def test_i_have_entered_a_new_course_start_date(step): +def test_i_have_entered_a_new_course_start_date(_step): set_date_or_time(COURSE_START_DATE_CSS, '12/22/2013') @step('The warning about course start date goes away$') -def test_the_warning_about_course_start_date_goes_away(step): +def test_the_warning_about_course_start_date_goes_away(_step): 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')) + assert 'error' not in world.css_find(COURSE_START_DATE_CSS).first._element.get_attribute('class') # pylint: disable=protected-access + assert 'error' not in world.css_find(COURSE_START_TIME_CSS).first._element.get_attribute('class') # pylint: disable=protected-access @step('my new course start date is shown$') -def new_course_start_date_is_shown(step): +def new_course_start_date_is_shown(_step): verify_date_or_time(COURSE_START_DATE_CSS, '12/22/2013') # Time should have stayed from before attempt to clear date. verify_date_or_time(COURSE_START_TIME_CSS, DUMMY_TIME) @step('I change fields$') -def test_i_change_fields(step): +def test_i_change_fields(_step): set_date_or_time(COURSE_START_DATE_CSS, '7/7/7777') set_date_or_time(COURSE_END_DATE_CSS, '7/7/7777') set_date_or_time(ENROLLMENT_START_DATE_CSS, '7/7/7777') @@ -140,7 +140,7 @@ def set_date_or_time(css, date_or_time): world.css_fill(css, date_or_time) e = world.css_find(css).first # hit Enter to apply the changes - e._element.send_keys(Keys.ENTER) + e._element.send_keys(Keys.ENTER) # pylint: disable=protected-access def verify_date_or_time(css, date_or_time): @@ -149,7 +149,7 @@ def verify_date_or_time(css, date_or_time): """ # We need to wait for JavaScript to fill in the field, so we use # css_has_value(), which first checks that the field is not blank - assert_true(world.css_has_value(css, date_or_time)) + assert world.css_has_value(css, date_or_time) @step('I do not see the changes') diff --git a/cms/djangoapps/contentstore/features/grading.py b/cms/djangoapps/contentstore/features/grading.py index 0fd0c03fc6..370a3af783 100644 --- a/cms/djangoapps/contentstore/features/grading.py +++ b/cms/djangoapps/contentstore/features/grading.py @@ -1,31 +1,32 @@ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name from lettuce import step, world -from nose.tools import assert_equal, assert_in, assert_not_equal from selenium.common.exceptions import InvalidElementStateException from common import * from contentstore.utils import reverse_course_url +from openedx.core.lib.tests.tools import assert_equal, assert_in, assert_not_equal # pylint: disable=no-name-in-module from terrain.steps import reload_the_page @step(u'I am viewing the grading settings') -def view_grading_settings(step): +def view_grading_settings(_step): world.click_course_settings() link_css = 'li.nav-course-settings-grading a' world.css_click(link_css) @step(u'I add "([^"]*)" new grade') -def add_grade(step, many): +def add_grade(_step, many): grade_css = '.new-grade-button' for __ in range(int(many)): world.css_click(grade_css) @step(u'I delete a grade') -def delete_grade(step): +def delete_grade(_step): #grade_css = 'li.grade-specific-bar > a.remove-button' #range_css = '.grade-specific-bar' #world.css_find(range_css)[1].mouseover() @@ -34,21 +35,21 @@ def delete_grade(step): @step(u'I see I now have "([^"]*)" grades$') -def view_grade_slider(step, how_many): +def view_grade_slider(_step, how_many): grade_slider_css = '.grade-specific-bar' all_grades = world.css_find(grade_slider_css) assert_equal(len(all_grades), int(how_many)) @step(u'I move a grading section') -def move_grade_slider(step): +def move_grade_slider(_step): moveable_css = '.ui-resizable-e' f = world.css_find(moveable_css).first - f.action_chains.drag_and_drop_by_offset(f._element, 100, 0).perform() + f.action_chains.drag_and_drop_by_offset(f._element, 100, 0).perform() # pylint: disable=protected-access @step(u'I see that the grade range has changed') -def confirm_change(step): +def confirm_change(_step): range_css = '.range' all_ranges = world.css_find(range_css) for i in range(len(all_ranges)): @@ -56,18 +57,18 @@ def confirm_change(step): @step(u'I change assignment type "([^"]*)" to "([^"]*)"$') -def change_assignment_name(step, old_name, new_name): +def change_assignment_name(_step, old_name, new_name): name_id = '#course-grading-assignment-name' index = get_type_index(old_name) f = world.css_find(name_id)[index] assert_not_equal(index, -1) for __ in xrange(len(old_name)): - f._element.send_keys(Keys.END, Keys.BACK_SPACE) - f._element.send_keys(new_name) + f._element.send_keys(Keys.END, Keys.BACK_SPACE) # pylint: disable=protected-access + f._element.send_keys(new_name) # pylint: disable=protected-access @step(u'I go back to the main course page') -def main_course_page(step): +def main_course_page(_step): main_page_link = reverse_course_url('course_handler', world.scenario_dict['COURSE'].id) world.visit(main_page_link) @@ -75,7 +76,7 @@ def main_course_page(step): @step(u'I do( not)? see the assignment name "([^"]*)"$') -def see_assignment_name(step, do_not, name): +def see_assignment_name(_step, _do_not, _name): # TODO: rewrite this once grading has been added back to the course outline pass # assignment_menu_css = 'ul.menu > li > a' @@ -94,32 +95,32 @@ def see_assignment_name(step, do_not, name): @step(u'I delete the assignment type "([^"]*)"$') -def delete_assignment_type(step, to_delete): +def delete_assignment_type(_step, to_delete): delete_css = '.remove-grading-data' world.css_click(delete_css, index=get_type_index(to_delete)) @step(u'I add a new assignment type "([^"]*)"$') -def add_assignment_type(step, new_name): +def add_assignment_type(_step, new_name): add_button_css = '.add-grading-data' world.css_click(add_button_css) name_id = '#course-grading-assignment-name' new_assignment = world.css_find(name_id)[-1] - new_assignment._element.send_keys(new_name) + new_assignment._element.send_keys(new_name) # pylint: disable=protected-access @step(u'I set the assignment weight to "([^"]*)"$') -def set_weight(step, weight): +def set_weight(_step, weight): weight_id = '#course-grading-assignment-gradeweight' weight_field = world.css_find(weight_id)[-1] old_weight = world.css_value(weight_id, -1) for __ in range(len(old_weight)): - weight_field._element.send_keys(Keys.END, Keys.BACK_SPACE) - weight_field._element.send_keys(weight) + weight_field._element.send_keys(Keys.END, Keys.BACK_SPACE) # pylint: disable=protected-access + weight_field._element.send_keys(weight) # pylint: disable=protected-access @step(u'the assignment weight is displayed as "([^"]*)"$') -def verify_weight(step, weight): +def verify_weight(_step, weight): weight_id = '#course-grading-assignment-gradeweight' assert_equal(world.css_value(weight_id, -1), weight) @@ -182,7 +183,7 @@ def i_change_grace_period(_step, grace_period): # this to happen, then we can end up with # an invalid value (e.g. "00:0048:00") # which prevents us from saving. - assert_true(world.css_has_value(grace_period_css, "00:00")) + assert world.css_has_value(grace_period_css, "00:00") # Set the new grace period ele.value = grace_period diff --git a/cms/djangoapps/contentstore/features/html-editor.py b/cms/djangoapps/contentstore/features/html-editor.py index 84497bee7d..06798d8cdb 100644 --- a/cms/djangoapps/contentstore/features/html-editor.py +++ b/cms/djangoapps/contentstore/features/html-editor.py @@ -1,12 +1,13 @@ # disable missing docstring # pylint: disable=missing-docstring +# pylint: disable=no-member from collections import OrderedDict from lettuce import step, world -from nose.tools import assert_equal, assert_false, assert_in, assert_true from common import get_codemirror_value, type_in_codemirror +from openedx.core.lib.tests.tools import assert_equal, assert_in # pylint: disable=no-name-in-module CODEMIRROR_SELECTOR_PREFIX = "$('iframe').contents().find" @@ -32,7 +33,7 @@ def i_created_raw_html(step): @step('I see the HTML component settings$') -def i_see_only_the_html_display_name(step): +def i_see_only_the_html_display_name(_step): world.verify_all_setting_entries( [ ['Display Name', "Text", False], @@ -53,12 +54,12 @@ def i_created_etext_in_latex(step): @step('I edit the page$') -def i_click_on_edit_icon(step): +def i_click_on_edit_icon(_step): world.edit_component() @step('I add an image with static link "(.*)" via the Image Plugin Icon$') -def i_click_on_image_plugin_icon(step, path): +def i_click_on_image_plugin_icon(_step, path): use_plugin( '.mce-i-image', lambda: world.css_fill('.mce-textbox', path, 0) @@ -66,7 +67,7 @@ def i_click_on_image_plugin_icon(step, path): @step('the link is shown as "(.*)" in the Image Plugin$') -def check_link_in_image_plugin(step, path): +def check_link_in_image_plugin(_step, path): use_plugin( '.mce-i-image', lambda: assert_equal(path, world.css_find('.mce-textbox')[0].value) @@ -74,7 +75,7 @@ def check_link_in_image_plugin(step, path): @step('I add a link with static link "(.*)" via the Link Plugin Icon$') -def i_click_on_link_plugin_icon(step, path): +def i_click_on_link_plugin_icon(_step, path): def fill_in_link_fields(): world.css_fill('.mce-textbox', path, 0) world.css_fill('.mce-textbox', 'picture', 1) @@ -83,7 +84,7 @@ def i_click_on_link_plugin_icon(step, path): @step('the link is shown as "(.*)" in the Link Plugin$') -def check_link_in_link_plugin(step, path): +def check_link_in_link_plugin(_step, path): # Ensure caret position is within the link just created. script = """ var editor = tinyMCE.activeEditor; @@ -98,25 +99,25 @@ def check_link_in_link_plugin(step, path): @step('type "(.*)" in the code editor and press OK$') -def type_in_codemirror_plugin(step, text): +def type_in_codemirror_plugin(_step, text): # Verify that raw code editor is not visible. - assert_true(world.css_has_class('.CodeMirror', 'is-inactive')) + assert world.css_has_class('.CodeMirror', 'is-inactive') # Verify that TinyMCE editor is present - assert_true(world.is_css_present('.tiny-mce')) + assert world.is_css_present('.tiny-mce') use_code_editor( lambda: type_in_codemirror(0, text, CODEMIRROR_SELECTOR_PREFIX) ) @step('and the code editor displays "(.*)"$') -def verify_code_editor_text(step, text): +def verify_code_editor_text(_step, text): use_code_editor( lambda: assert_equal(text, get_codemirror_value(0, CODEMIRROR_SELECTOR_PREFIX)) ) @step('I save the page$') -def i_click_on_save(step): +def i_click_on_save(_step): world.save_component() @@ -131,7 +132,7 @@ def check_raw_editor_text(step): @step('the src link is rewritten to the asset link "(.*)"$') -def image_static_link_is_rewritten(step, path): +def image_static_link_is_rewritten(_step, path): # Find the TinyMCE iframe within the main window with world.browser.get_iframe('mce_0_ifr') as tinymce: image = tinymce.find_by_tag('img').first @@ -139,7 +140,7 @@ def image_static_link_is_rewritten(step, path): @step('the href link is rewritten to the asset link "(.*)"$') -def link_static_link_is_rewritten(step, path): +def link_static_link_is_rewritten(_step, path): # Find the TinyMCE iframe within the main window with world.browser.get_iframe('mce_0_ifr') as tinymce: link = tinymce.find_by_tag('a').first @@ -147,7 +148,7 @@ def link_static_link_is_rewritten(step, path): @step('the expected toolbar buttons are displayed$') -def check_toolbar_buttons(step): +def check_toolbar_buttons(_step): dropdowns = world.css_find('.mce-listbox') assert_equal(2, len(dropdowns)) @@ -184,12 +185,12 @@ def check_toolbar_buttons(step): assert_equal(len(expected_buttons), len(buttons)) for index, button in enumerate(expected_buttons): - class_names = buttons[index]._element.get_attribute('class') + class_names = buttons[index]._element.get_attribute('class') # pylint: disable=protected-access assert_equal("mce-ico mce-i-" + button, class_names) @step('I set the text to "(.*)" and I select the text$') -def set_text_and_select(step, text): +def set_text_and_select(_step, text): script = """ var editor = tinyMCE.activeEditor; editor.setContent(arguments[0]); @@ -199,35 +200,35 @@ def set_text_and_select(step, text): @step('I select the code toolbar button$') -def select_code_button(step): +def select_code_button(_step): # This is our custom "code style" button. It uses an image instead of a class. world.css_click(".mce-i-none") @step('type "(.*)" into the Raw Editor$') -def type_in_raw_editor(step, text): +def type_in_raw_editor(_step, text): # Verify that CodeMirror editor is not hidden - assert_false(world.css_has_class('.CodeMirror', 'is-inactive')) + assert not world.css_has_class('.CodeMirror', 'is-inactive') # Verify that TinyMCE Editor is not present - assert_true(world.is_css_not_present('.tiny-mce')) + assert world.is_css_not_present('.tiny-mce') type_in_codemirror(0, text) @step('I edit the component and select the (Raw|Visual) Editor$') -def select_editor(step, editor): +def select_editor(_step, editor): world.edit_component_and_select_settings() world.browser.select('Editor', editor) @step('I click font selection dropdown') -def click_font_dropdown(step): +def click_font_dropdown(_step): dropdowns = [drop for drop in world.css_find('.mce-listbox') if drop.text == 'Font Family'] assert_equal(len(dropdowns), 1) dropdowns[0].click() @step('I should see a list of available fonts') -def font_selector_dropdown_is_shown(step): +def font_selector_dropdown_is_shown(_step): font_panel = get_fonts_list_panel(world) expected_fonts = list(CUSTOM_FONTS.keys()) + list(TINYMCE_FONTS.keys()) actual_fonts = [font.strip() for font in font_panel.text.split('\n')] @@ -244,7 +245,7 @@ def default_options_sets_expected_font_family(step): # pylint: disable=unused-a @step('all standard tinyMCE fonts should be available') -def check_standard_tinyMCE_fonts(step): +def check_standard_tinyMCE_fonts(_step): fonts = get_available_fonts(get_fonts_list_panel(world)) for label, expected_fonts in TINYMCE_FONTS.items(): for expected_font in expected_fonts: @@ -318,4 +319,4 @@ def get_font_family(font_span): # get_attribute('style').replace('font-family: ', '').replace(';', '') is equivalent to # value_of_css_property('font-family'). However, for reason unknown value_of_css_property fails tests in CI # while works as expected in local development environment - return font_span._element.get_attribute('style').replace('font-family: ', '').replace(';', '') + return font_span._element.get_attribute('style').replace('font-family: ', '').replace(';', '') # pylint: disable=protected-access diff --git a/cms/djangoapps/contentstore/features/pages.py b/cms/djangoapps/contentstore/features/pages.py index 4149af0228..3a09b0d7a2 100644 --- a/cms/djangoapps/contentstore/features/pages.py +++ b/cms/djangoapps/contentstore/features/pages.py @@ -4,7 +4,7 @@ # pylint: disable=no-member from lettuce import step, world -from nose.tools import assert_equal, assert_in +from openedx.core.lib.tests.tools import assert_equal, assert_in # pylint: disable=no-name-in-module CSS_FOR_TAB_ELEMENT = "li[data-tab-id='{0}'] input.toggle-checkbox" diff --git a/cms/djangoapps/contentstore/features/problem-editor.py b/cms/djangoapps/contentstore/features/problem-editor.py index 8ff30ef7df..4df8d871b7 100644 --- a/cms/djangoapps/contentstore/features/problem-editor.py +++ b/cms/djangoapps/contentstore/features/problem-editor.py @@ -1,14 +1,15 @@ # disable missing docstring # pylint: disable=missing-docstring +# pylint: disable=no-member import json from lettuce import step, world -from nose.tools import assert_equal, assert_true +from openedx.core.lib.tests.tools import assert_equal, assert_true # pylint: disable=no-name-in-module -from advanced_settings import ADVANCED_MODULES_KEY, change_value -from common import open_new_course, type_in_codemirror -from course_import import import_file +from cms.djangoapps.contentstore.features.advanced_settings import ADVANCED_MODULES_KEY, change_value +from cms.djangoapps.contentstore.features.common import open_new_course, type_in_codemirror +from cms.djangoapps.contentstore.features.course_import import import_file DISPLAY_NAME = "Display Name" MAXIMUM_ATTEMPTS = "Maximum Attempts" @@ -57,7 +58,7 @@ def i_create_new_common_problem(step): @step('when I mouseover on "(.*)"') -def i_mouseover_on_html_component(step, element_class): +def i_mouseover_on_html_component(_step, element_class): action_css = '.{}'.format(element_class) world.trigger_event(action_css, event='mouseover') @@ -96,7 +97,7 @@ def i_edit_and_select_settings(_step): @step('I see the advanced settings and their expected values$') -def i_see_advanced_settings_with_values(step): +def i_see_advanced_settings_with_values(_step): world.verify_all_setting_entries( [ [DISPLAY_NAME, "Blank Common Problem", True], @@ -126,7 +127,7 @@ def my_display_name_change_is_persisted_on_save(step): @step('the problem display name is "(.*)"$') -def verify_problem_display_name(step, name): +def verify_problem_display_name(_step, name): """ name is uppercased because the heading styles are uppercase in css """ @@ -277,7 +278,7 @@ def edit_latex_source(_step): @step('my change to the High Level Source is persisted') def high_level_source_persisted(_step): - def verify_text(driver): + def verify_text(_driver): css_sel = '.problem div>span' return world.css_text(css_sel) == 'hi' @@ -291,7 +292,7 @@ def high_level_source_in_editor(_step): @step(u'I have an empty course') -def i_have_empty_course(step): +def i_have_empty_course(_step): open_new_course() @@ -370,7 +371,8 @@ def verify_modified_display_name_with_special_chars(): def verify_modified_display_name_with_html(): - world.verify_setting_entry(world.get_setting_entry(DISPLAY_NAME), DISPLAY_NAME, "", True) + world.verify_setting_entry(world.get_setting_entry(DISPLAY_NAME), + DISPLAY_NAME, "", True) def verify_unset_display_name(): diff --git a/cms/djangoapps/contentstore/features/signup.py b/cms/djangoapps/contentstore/features/signup.py index dfcf29e279..e0b2ca9349 100644 --- a/cms/djangoapps/contentstore/features/signup.py +++ b/cms/djangoapps/contentstore/features/signup.py @@ -1,12 +1,11 @@ # pylint: disable=missing-docstring -# pylint: disable=redefined-outer-name +# pylint: disable=no-member from lettuce import step, world -from nose.tools import assert_false, assert_true @step('I fill in the registration form$') -def i_fill_in_the_registration_form(step): +def i_fill_in_the_registration_form(_step): def fill_in_reg_form(): register_form = world.css_find('form#register_form') register_form.find_by_name('email').fill('robot+studio@edx.org') @@ -18,19 +17,19 @@ def i_fill_in_the_registration_form(step): @step('I press the Create My Account button on the registration form$') -def i_press_the_button_on_the_registration_form(step): +def i_press_the_button_on_the_registration_form(_step): submit_css = 'form#register_form button#submit' world.css_click(submit_css) @step('I should see an email verification prompt') -def i_should_see_an_email_verification_prompt(step): +def i_should_see_an_email_verification_prompt(_step): world.css_has_text('h1.page-header', u'Studio Home') world.css_has_text('div.msg h3.title', u'We need to verify your email address') @step(u'I fill in and submit the signin form$') -def i_fill_in_the_signin_form(step): +def i_fill_in_the_signin_form(_step): def fill_login_form(): login_form = world.browser.find_by_css('form#login_form') login_form.find_by_name('email').fill('robot+studio@edx.org') @@ -40,18 +39,18 @@ def i_fill_in_the_signin_form(step): @step(u'I should( not)? see a login error message$') -def i_should_see_a_login_error(step, should_not_see): +def i_should_see_a_login_error(_step, should_not_see): if should_not_see: # the login error may be absent or invisible. Check absence first, # because css_visible will throw an exception if the element is not present if world.is_css_present('div#login_error'): - assert_false(world.css_visible('div#login_error')) + assert not world.css_visible('div#login_error') else: - assert_true(world.css_visible('div#login_error')) + assert world.css_visible('div#login_error') @step(u'I fill in and submit the signin form incorrectly$') -def i_goof_in_the_signin_form(step): +def i_goof_in_the_signin_form(_step): def fill_login_form(): login_form = world.browser.find_by_css('form#login_form') login_form.find_by_name('email').fill('robot+studio@edx.org') @@ -61,12 +60,12 @@ def i_goof_in_the_signin_form(step): @step(u'I edit the password field$') -def i_edit_the_password_field(step): +def i_edit_the_password_field(_step): password_css = 'form#login_form input#password' world.css_fill(password_css, 'test') @step(u'I submit the signin form$') -def i_submit_the_signin_form(step): +def i_submit_the_signin_form(_step): submit_css = 'form#login_form button#submit' world.css_click(submit_css) diff --git a/common/djangoapps/terrain/steps.py b/common/djangoapps/terrain/steps.py index 7016a6b752..e4114ff6b9 100644 --- a/common/djangoapps/terrain/steps.py +++ b/common/djangoapps/terrain/steps.py @@ -18,9 +18,10 @@ from logging import getLogger # it to get the correct value import lettuce.django from lettuce import step, world -from nose.tools import assert_equals # pylint: disable=no-name-in-module from opaque_keys.edx.keys import CourseKey +from openedx.core.lib.tests.tools import assert_equals # pylint: disable=no-name-in-module + from .course_helpers import * from .ui_helpers import * diff --git a/common/djangoapps/terrain/ui_helpers.py b/common/djangoapps/terrain/ui_helpers.py index 13748c5ca8..753c60f4ae 100644 --- a/common/djangoapps/terrain/ui_helpers.py +++ b/common/djangoapps/terrain/ui_helpers.py @@ -12,7 +12,6 @@ from urllib import quote_plus # it to get the correct value import lettuce.django from lettuce import world -from nose.tools import assert_true from selenium.common.exceptions import ( InvalidElementStateException, StaleElementReferenceException, @@ -23,6 +22,8 @@ from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait +from openedx.core.lib.tests.tools import assert_true + GLOBAL_WAIT_FOR_TIMEOUT = 60 REQUIREJS_WAIT = { diff --git a/lms/djangoapps/courseware/features/common.py b/lms/djangoapps/courseware/features/common.py index 79e17f4816..f07fa08d93 100644 --- a/lms/djangoapps/courseware/features/common.py +++ b/lms/djangoapps/courseware/features/common.py @@ -1,4 +1,5 @@ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name from __future__ import absolute_import @@ -228,9 +229,9 @@ def get_courseware_with_tabs(course_id): 'chapter_name': c.display_name_with_default_escaped, 'sections': [{ 'section_name': s.display_name_with_default_escaped, - 'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0, + 'clickable_tab_count': len(s.get_children()) if isinstance(s, seq_module.SequenceDescriptor) else 0, 'tabs': [{ - 'children_count': len(t.get_children()) if (type(t) == vertical_block.VerticalBlock) else 0, + 'children_count': len(t.get_children()) if isinstance(t, vertical_block.VerticalBlock) else 0, 'class': t.__class__.__name__} for t in s.get_children() ] } for s in c.get_children() if not s.hide_from_toc] diff --git a/lms/djangoapps/courseware/features/events.py b/lms/djangoapps/courseware/features/events.py index f86b2c8544..3133186fce 100644 --- a/lms/djangoapps/courseware/features/events.py +++ b/lms/djangoapps/courseware/features/events.py @@ -2,9 +2,10 @@ from django.conf import settings from lettuce import before, step, world -from nose.tools import assert_equals, assert_in from pymongo import MongoClient +from openedx.core.lib.tests.tools import assert_equals, assert_in # pylint: disable=no-name-in-module + REQUIRED_EVENT_FIELDS = [ 'agent', 'event', @@ -18,25 +19,25 @@ REQUIRED_EVENT_FIELDS = [ ] -@before.all +@before.all # pylint: disable=no-member def connect_to_mongodb(): world.mongo_client = MongoClient(host=settings.MONGO_HOST, port=settings.MONGO_PORT_NUM) world.event_collection = world.mongo_client['track']['events'] -@before.each_scenario +@before.each_scenario # pylint: disable=no-member def reset_captured_events(_scenario): world.event_collection.drop() -@before.outline -def reset_between_outline_scenarios(_scenario, order, outline, reasons_to_fail): +@before.outline # pylint: disable=no-member +def reset_between_outline_scenarios(_scenario, _order, _outline, _reasons_to_fail): world.event_collection.drop() @step(r'[aA]n? course url "(.*)" event is emitted$') def course_url_event_is_emitted(_step, url_regex): - event_type = url_regex.format(world.scenario_dict['COURSE'].id) + event_type = url_regex.format(world.scenario_dict['COURSE'].id) # pylint: disable=no-member n_events_are_emitted(_step, 1, event_type, "server") @@ -71,7 +72,7 @@ def n_events_are_emitted(_step, count, event_type, event_source): event = cursor.next() expected_field_values = { - "username": world.scenario_dict['USER'].username, + "username": world.scenario_dict['USER'].username, # pylint: disable=no-member "event_type": event_type, } for key, value in expected_field_values.iteritems(): diff --git a/lms/djangoapps/courseware/features/lti.py b/lms/djangoapps/courseware/features/lti.py index 282039354f..5995938db2 100644 --- a/lms/djangoapps/courseware/features/lti.py +++ b/lms/djangoapps/courseware/features/lti.py @@ -1,4 +1,5 @@ # pylint: disable=missing-docstring +# pylint: disable=no-member import datetime import os @@ -6,14 +7,13 @@ import pytz from django.conf import settings from lettuce import step, world from mock import patch -from nose.tools import assert_equal, assert_in, assert_is_none, assert_true from pytz import UTC -from selenium.common.exceptions import NoAlertPresentException from splinter.exceptions import ElementDoesNotExist from common import visit_scenario_item from courseware.access import has_access from courseware.tests.factories import BetaTesterFactory, InstructorFactory +from openedx.core.lib.tests.tools import assert_equal, assert_in, assert_true # pylint: disable=no-name-in-module from student.tests.factories import UserFactory TEST_COURSE_NAME = "test_course_a" diff --git a/lms/djangoapps/instructor/features/common.py b/lms/djangoapps/instructor/features/common.py index 4342398f81..f191ba1a46 100644 --- a/lms/djangoapps/instructor/features/common.py +++ b/lms/djangoapps/instructor/features/common.py @@ -3,15 +3,16 @@ Define common steps for instructor dashboard acceptance tests. """ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name from __future__ import absolute_import from lettuce import step, world from mock import patch -from nose.tools import assert_in from courseware.tests.factories import InstructorFactory, StaffFactory +from openedx.core.lib.tests.tools import assert_in # pylint: disable=no-name-in-module @step(u'Given I am "([^"]*)" for a very large course') @@ -122,7 +123,7 @@ def click_a_button(step, button): # pylint: disable=unused-argument @step(u'I visit the "([^"]*)" tab') -def click_a_button(step, tab_name): # pylint: disable=unused-argument +def click_a_tab(step, tab_name): # pylint: disable=unused-argument # course_info, membership, student_admin, data_download, analytics, send_email tab_name_dict = { 'Course Info': 'course_info', diff --git a/lms/djangoapps/instructor/features/data_download.py b/lms/djangoapps/instructor/features/data_download.py index 5a050867b7..3de43355b7 100644 --- a/lms/djangoapps/instructor/features/data_download.py +++ b/lms/djangoapps/instructor/features/data_download.py @@ -4,14 +4,16 @@ acceptance tests. """ # pylint: disable=missing-docstring +# pylint: disable=no-member # pylint: disable=redefined-outer-name from django.utils import http from lettuce import step, world -from nose.tools import assert_in, assert_regexp_matches from terrain.steps import reload_the_page +from openedx.core.lib.tests.tools import assert_in, assert_regexp_matches # pylint: disable=no-name-in-module + @step(u'I see a table of student profiles') def find_student_profile_table(step): # pylint: disable=unused-argument diff --git a/openedx/core/lib/tests/tools.py b/openedx/core/lib/tests/tools.py new file mode 100644 index 0000000000..f18a0685a3 --- /dev/null +++ b/openedx/core/lib/tests/tools.py @@ -0,0 +1,43 @@ +""" +Copy of the useful parts of nose.tools. This is only used for lettuce test +utility functions, which neither use pytest nor have access to a TestCase +instance. This module should be deleted once the last lettuce tests have +been ported over to bok-choy. + +Tracebacks should not descend into these functions. +We define the ``__unittest`` symbol in their module namespace so unittest will +skip them when printing tracebacks, just as it does for their corresponding +methods in ``unittest`` proper. +""" +import re +import unittest + +__all__ = [] + +# Use the same flag as unittest itself to prevent descent into these functions: +__unittest = 1 + +# Expose assert* from unittest.TestCase +# - give them pep8 style names +caps = re.compile('([A-Z])') + + +def pep8(name): + return caps.sub(lambda m: '_' + m.groups()[0].lower(), name) + + +class Dummy(unittest.TestCase): + def noop(self): + pass + + +_t = Dummy('noop') + +for at in [at for at in dir(_t) if at.startswith('assert') and '_' not in at]: + pepd = pep8(at) + vars()[pepd] = getattr(_t, at) + __all__.append(pepd) + +del Dummy +del _t +del pep8