From be5ccf92e75e9e552b804d3f1a8ec9d0d0f2aa14 Mon Sep 17 00:00:00 2001 From: Agha Awais Date: Tue, 31 Jul 2018 12:31:11 +0000 Subject: [PATCH] advanced settings bokchoy tests III --- .../features/advanced_settings.feature | 39 ------ .../features/advanced_settings.py | 123 +----------------- .../pages/studio/settings_advanced.py | 16 ++- .../tests/studio/test_studio_settings.py | 91 ++++++++++++- 4 files changed, 105 insertions(+), 164 deletions(-) delete mode 100644 cms/djangoapps/contentstore/features/advanced_settings.feature diff --git a/cms/djangoapps/contentstore/features/advanced_settings.feature b/cms/djangoapps/contentstore/features/advanced_settings.feature deleted file mode 100644 index 6f1003b171..0000000000 --- a/cms/djangoapps/contentstore/features/advanced_settings.feature +++ /dev/null @@ -1,39 +0,0 @@ -@shard_1 -Feature: CMS.Advanced (manual) course policy - In order to specify course policy settings for which no custom user interface exists - I want to be able to manually enter JSON key /value pairs - - # Sauce labs does not play nicely with CodeMirror - @skip_sauce - Scenario: Test how multi-line input appears - Given I am on the Advanced Course Settings page in Studio - When I create a JSON object as a value for "Discussion Topic Mapping" - Then it is displayed as formatted - And I reload the page - Then it is displayed as formatted - - # Sauce labs does not play nicely with CodeMirror - @skip_sauce - Scenario: Test error if value supplied is of the wrong type - Given I am on the Advanced Course Settings page in Studio - When I create a JSON object as a value for "Course Display Name" - Then I get an error on save - 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 - # Sauce labs does not play nicely with CodeMirror - @skip_sauce - 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 - Then it is displayed as a string - And I reload the page - Then it is displayed as a string - - Scenario: Deprecated Settings can be toggled - Given I am on the Advanced Course Settings page in Studio - When I toggle the display of deprecated settings - Then deprecated settings are then shown - And I toggle the display of deprecated settings - Then deprecated settings are not shown diff --git a/cms/djangoapps/contentstore/features/advanced_settings.py b/cms/djangoapps/contentstore/features/advanced_settings.py index 949211fd6a..48b7787799 100644 --- a/cms/djangoapps/contentstore/features/advanced_settings.py +++ b/cms/djangoapps/contentstore/features/advanced_settings.py @@ -2,122 +2,10 @@ # pylint: disable=redefined-outer-name from lettuce import step, world -from nose.tools import assert_equal, assert_false, assert_regexp_matches - -from common import get_codemirror_value, press_the_notification_button, type_in_codemirror +from cms.djangoapps.contentstore.features.common import press_the_notification_button, type_in_codemirror KEY_CSS = '.key h3.title' -DISPLAY_NAME_KEY = "Course Display Name" -DISPLAY_NAME_VALUE = '"Robot Super Course"' ADVANCED_MODULES_KEY = "Advanced Module List" -# A few deprecated settings for testing toggling functionality. -DEPRECATED_SETTINGS = ["CSS Class for Course Reruns", "Hide Progress Tab", "XQA Key"] - - -@step('I select the Advanced Settings$') -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 - # 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) - - -@step('I am on the Advanced Course Settings page in Studio$') -def i_am_on_advanced_course_settings(step): - step.given('I have opened a new course in Studio') - step.given('I select the Advanced Settings') - - -@step(u'I edit the value of a policy key$') -def edit_the_value_of_a_policy_key(step): - type_in_codemirror(get_index_of(DISPLAY_NAME_KEY), 'X') - - -@step(u'I edit the value of a policy key and save$') -def edit_the_value_of_a_policy_key_and_save(step): - change_display_name_value(step, '"foo"') - - -@step('I create a JSON object as a value for "(.*)"$') -def create_JSON_object(step, key): - change_value(step, key, '{"key": "value", "key_2": "value_2"}') - - -@step('I create a non-JSON value not in quotes$') -def create_value_not_in_quotes(step): - change_display_name_value(step, 'quote me') - - -@step('it is displayed as formatted$') -def it_is_formatted(step): - assert_policy_entries(['Discussion Topic Mapping'], ['{\n "key": "value",\n "key_2": "value_2"\n}']) - - -@step('I get an error on save$') -def error_on_save(step): - assert_regexp_matches( - world.css_text('.error-item-message'), - "Value stored in a .* must be .*, found .*" - ) - - -@step('it is displayed as a string') -def it_is_displayed_as_string(step): - assert_policy_entries([DISPLAY_NAME_KEY], ['"quote me"']) - - -@step(u'the policy key value is unchanged$') -def the_policy_key_value_is_unchanged(step): - assert_equal(get_display_name_value(), DISPLAY_NAME_VALUE) - - -@step(u'the policy key value is changed$') -def the_policy_key_value_is_changed(step): - assert_equal(get_display_name_value(), '"foo"') - - -@step(u'deprecated settings are (then|not) shown$') -def verify_deprecated_settings_shown(_step, expected): - for setting in DEPRECATED_SETTINGS: - if expected == "not": - assert_equal(-1, get_index_of(setting)) - else: - world.wait_for(lambda _: get_index_of(setting) != -1) - - -@step(u'I toggle the display of deprecated settings$') -def toggle_deprecated_settings(_step): - world.css_click(".deprecated-settings-label") - - -def assert_policy_entries(expected_keys, expected_values): - for key, value in zip(expected_keys, expected_values): - index = get_index_of(key) - assert_false(index == -1, "Could not find key: {key}".format(key=key)) - found_value = get_codemirror_value(index) - assert_equal( - value, found_value, - "Expected {} to have value {} but found {}".format(key, value, found_value) - ) def get_index_of(expected_key): @@ -130,15 +18,6 @@ def get_index_of(expected_key): return -1 -def get_display_name_value(): - index = get_index_of(DISPLAY_NAME_KEY) - return get_codemirror_value(index) - - -def change_display_name_value(step, new_value): - change_value(step, DISPLAY_NAME_KEY, new_value) - - def change_value(step, key, new_value): index = get_index_of(key) type_in_codemirror(index, new_value) diff --git a/common/test/acceptance/pages/studio/settings_advanced.py b/common/test/acceptance/pages/studio/settings_advanced.py index 3e0b99627a..2fd3cf858d 100644 --- a/common/test/acceptance/pages/studio/settings_advanced.py +++ b/common/test/acceptance/pages/studio/settings_advanced.py @@ -51,12 +51,23 @@ class AdvancedSettingsPage(CoursePage): """ return self.q(css=DEPRECATED_SETTINGS_BUTTON_SELECTOR).text[0] - def check_deprecated_settings_visibility(self): + def is_deprecated_setting_visible(self): """ Returns true if deprecated settings are visible """ return self.q(css=DEPRECATED_SETTINGS_SELECTOR).visible + def toggle_deprecated_settings(self): + """ + Show deprecated Settings + """ + button_text = self.deprecated_settings_button_text + self.q(css=DEPRECATED_SETTINGS_BUTTON_SELECTOR).click() + if button_text == 'Show Deprecated Settings': + self.wait_for_element_presence(DEPRECATED_SETTINGS_SELECTOR, 'Deprecated Settings are present') + else: + self.wait_for_element_absence(DEPRECATED_SETTINGS_SELECTOR, 'Deprecated Settings are not present') + def wait_for_modal_load(self): """ Wait for validation response from the server, and make sure that @@ -134,6 +145,9 @@ class AdvancedSettingsPage(CoursePage): return self.q(css=ERROR_ITEM_CONTENT_SELECTOR).text def _get_index_of(self, expected_key): + """ + Returns the index of expected key + """ for i, element in enumerate(self.q(css=KEY_CSS)): # Sometimes get stale reference if I hold on to the array of elements key = self.q(css=KEY_CSS).nth(i).text[0] diff --git a/common/test/acceptance/tests/studio/test_studio_settings.py b/common/test/acceptance/tests/studio/test_studio_settings.py index 2b0285b125..596637e055 100644 --- a/common/test/acceptance/tests/studio/test_studio_settings.py +++ b/common/test/acceptance/tests/studio/test_studio_settings.py @@ -7,13 +7,14 @@ from __future__ import unicode_literals import os import random import string +import json from textwrap import dedent from bok_choy.promise import EmptyPromise from mock import patch from nose.plugins.attrib import attr -from base_studio_test import StudioCourseTest +from common.test.acceptance.tests.studio.base_studio_test import StudioCourseTest from common.test.acceptance.fixtures.course import XBlockFixtureDesc from common.test.acceptance.pages.common.utils import add_enrollment_course_modes from common.test.acceptance.pages.lms.courseware import CoursewarePage @@ -435,7 +436,93 @@ class AdvancedSettingsValidationTest(StudioCourseTest): """ button_text = self.advanced_settings.deprecated_settings_button_text self.assertEqual(button_text, 'Show Deprecated Settings') - self.assertFalse(self.advanced_settings.check_deprecated_settings_visibility()) + self.assertFalse(self.advanced_settings.is_deprecated_setting_visible()) + + def test_deprecated_settings_can_be_toggled(self): + """ + Scenario: Test that advanced settings can toggle deprecated settings + Given I am on the Advanced Course Settings page in Studio + When I toggle the display of deprecated settings + Then deprecated settings are then shown + And I toggle the display of deprecated settings + Then deprecated settings are not shown + """ + + self.advanced_settings.toggle_deprecated_settings() + button_text = self.advanced_settings.deprecated_settings_button_text + self.assertEqual( + button_text, + 'Hide Deprecated Settings', + "Button text should change to 'Hide Deprecated Settings' after the click" + ) + self.assertTrue(self.advanced_settings.is_deprecated_setting_visible()) + self.advanced_settings.toggle_deprecated_settings() + self.assertFalse(self.advanced_settings.is_deprecated_setting_visible()) + self.assertEqual( + self.advanced_settings.deprecated_settings_button_text, + 'Show Deprecated Settings', + "Button text should change to 'Show Deprecated Settings' after the click" + ) + + def test_multi_line_input(self): + """ + Scenario: Test that advanced settings correctly shows the multi-line input + Given I am on the Advanced Course Settings page in Studio + When I create a JSON object as a value for "Discussion Topic Mapping" + Then it is displayed as formatted + """ + + inputs = { + "key": "value", + "key_2": "value_2" + } + json_input = json.dumps(inputs) + self.advanced_settings.set('Discussion Topic Mapping', json_input) + self.assertEqual( + self.advanced_settings.get('Discussion Topic Mapping'), + '{\n "key": "value",\n "key_2": "value_2"\n}' + ) + + def test_automatic_quoting_of_non_json_value(self): + """ + Scenario: Test that advanced settings automatically quotes the field input + upon saving + Given I am on the Advanced Course Settings page in Studio + When I create a non-JSON value not in quotes + Then it is displayed as a string + """ + + self.advanced_settings.set(self.course_name_key, self.course_name_value) + self.assertEqual( + self.advanced_settings.get(self.course_name_key), + '"Test Name"' + ) + + def test_validation_error_for_wrong_input_type(self): + """ + Scenario: Test error if value supplied is of the wrong type + Given I am on the Advanced Course Settings page in Studio + When I create a JSON object as a value for "Course Display Name" + Then I get an error on save + And I reload the page + Then the policy key value is unchanged + """ + + course_display_name = self.advanced_settings.get('Course Display Name') + inputs = { + "key": "value", + "key_2": "value_2" + } + json_input = json.dumps(inputs) + self.advanced_settings.set('Course Display Name', json_input) + self.advanced_settings.wait_for_modal_load() + self.check_modal_shows_correct_contents(['Course Display Name']) + self.advanced_settings.refresh_and_wait_for_load() + self.assertEquals( + self.advanced_settings.get('Course Display Name'), + course_display_name, + 'Wrong input for Course Display Name must not change its value' + ) def test_modal_shows_one_validation_error(self): """