class AdvancedSettingsValidationTest(StudioCourseTest):
    """
    Tests for validation feature in Studio's advanced settings tab
    """
    def setUp(self):
        super(AdvancedSettingsValidationTest, self).setUp()
        self.advanced_settings = AdvancedSettingsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.type_fields = ['Course Display Name', 'Advanced Module List', 'Discussion Topic Mapping',
                            'Maximum Attempts', 'Course Announcement Date']

        # Before every test, make sure to visit the page first
        self.advanced_settings.visit()

    def test_modal_shows_one_validation_error(self):
        """
        Test that advanced settings don't save if there's a single wrong input,
        and that it shows the correct error message in the modal.
        """

        # Feed an integer value for String field.
        # .set method saves automatically after setting a value
        course_display_name = self.advanced_settings.get('Course Display Name')
        self.advanced_settings.set('Course Display Name', 1)
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        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_multiple_validation_errors(self):
        """
        Test that advanced settings don't save with multiple wrong inputs
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        self.check_modal_shows_correct_contents(self.type_fields)
        self.advanced_settings.refresh_and_wait_for_load()

        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key),
                val,
                'Wrong input for Advanced Settings Fields must not change its value'
            )

    def test_undo_changes(self):
        """
        Test that undo changes button in the modal resets all settings changes
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()

        # Let modal popup
        self.advanced_settings.wait_for_modal_load()

        # Click Undo Changes button
        self.advanced_settings.undo_changes_via_modal()

        # Check that changes are undone
        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key),
                val,
                'Undoing Should revert back to original value'
            )

    def test_manual_change(self):
        """
        Test that manual changes button in the modal keeps settings unchanged
        """
        inputs = {"Course Display Name": 1,
                  "Advanced Module List": 1,
                  "Discussion Topic Mapping": 1,
                  "Maximum Attempts": '"string"',
                  "Course Announcement Date": '"string"',
                  }

        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()
        self.advanced_settings.trigger_manual_changes()

        # Check that the validation modal went away.
        self.assertFalse(self.advanced_settings.is_validation_modal_present())

        # Iterate through the wrong values and make sure they're still displayed
        for key, val in inputs.iteritems():
            self.assertEquals(
                str(self.advanced_settings.get(key)),
                str(val),
                'manual change should keep: ' + str(val) + ', but is: ' + str(self.advanced_settings.get(key))
            )

    def check_modal_shows_correct_contents(self, wrong_settings_list):
        """
        Helper function that checks if the validation modal contains correct
        error messages.
        """
        # Check presence of modal
        self.assertTrue(self.advanced_settings.is_validation_modal_present())

        # List of wrong settings item & what is presented in the modal should be the same
        error_item_names = self.advanced_settings.get_error_item_names()
        self.assertEqual(set(wrong_settings_list), set(error_item_names))

        error_item_messages = self.advanced_settings.get_error_item_messages()
        self.assertEqual(len(error_item_names), len(error_item_messages))

    def get_settings_fields_of_each_type(self):
        """
        Get one of each field type:
           - String: Course Display Name
           - List: Advanced Module List
           - Dict: Discussion Topic Mapping
           - Integer: Maximum Attempts
           - Date: Course Announcement Date
        """
        return {
            "Course Display Name": self.advanced_settings.get('Course Display Name'),
            "Advanced Module List": self.advanced_settings.get('Advanced Module List'),
            "Discussion Topic Mapping": self.advanced_settings.get('Discussion Topic Mapping'),
            "Maximum Attempts": self.advanced_settings.get('Maximum Attempts'),
            "Course Announcement Date": self.advanced_settings.get('Course Announcement Date'),
        }

    def set_wrong_inputs_to_fields(self):
        """
        Set wrong values for the chosen fields
        """
        self.advanced_settings.set_values(
            {
                "Course Display Name": 1,
                "Advanced Module List": 1,
                "Discussion Topic Mapping": 1,
                "Maximum Attempts": '"string"',
                "Course Announcement Date": '"string"',
            }
        )

    def test_only_expected_fields_are_displayed(self):
        """
        Scenario: The Advanced Settings screen displays settings/fields not specifically hidden from
        view by a developer.
        Given I have a set of CourseMetadata fields defined for the course
        When I view the Advanced Settings screen for the course
        The total number of fields displayed matches the number I expect
        And the actual fields displayed match the fields I expect to see
        """
        expected_fields = self.advanced_settings.expected_settings_names
        displayed_fields = self.advanced_settings.displayed_settings_names
        self.assertEquals(set(displayed_fields), set(expected_fields))
class AdvancedSettingsValidationTest(StudioCourseTest):
    """
    Tests for validation feature in Studio's advanced settings tab
    """
    course_name_key = 'Course Display Name'
    course_name_value = 'Test Name'

    def setUp(self):
        super(AdvancedSettingsValidationTest, self).setUp()
        self.advanced_settings = AdvancedSettingsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.type_fields = ['Course Display Name', 'Advanced Module List', 'Discussion Topic Mapping',
                            'Maximum Attempts', 'Course Announcement Date']

        # Before every test, make sure to visit the page first
        self.advanced_settings.visit()

    def test_course_author_sees_default_advanced_settings(self):
        """
        Scenario: Test that advanced settings have the default settings
            Given a staff logs in to studio
            When this user goes to advanced settings page
                Then this user sees 'Allow Anonymous Discussion Posts' as true
                And 'Enable Timed Exams' as false
                And 'Maximum Attempts' as null
        """
        anonymous_discussion_setting = self.advanced_settings.get('Allow Anonymous Discussion Posts')
        timed_exam_settings = self.advanced_settings.get('Enable Timed Exams')
        max_attempts = self.advanced_settings.get('Maximum Attempts')
        page_default_settings = [
            anonymous_discussion_setting,
            timed_exam_settings,
            max_attempts
        ]
        default_anonymous_discussion_setting = 'true'
        default_timed_exam_settings = 'false'
        default_max_attempts = 'null'
        expected_default_settings = [
            default_anonymous_discussion_setting,
            default_timed_exam_settings,
            default_max_attempts
        ]
        self.assertEqual(
            page_default_settings,
            expected_default_settings
        )

    def test_keys_appear_alphabetically(self):
        """
        Scenario: Test that advanced settings have all the keys in alphabetic order
            Given a staff logs in to studio
            When this user goes to advanced settings page
                Then he sees all the advanced setting keys in alphabetic order
        """

        key_names = self.advanced_settings.key_names
        self.assertEqual(key_names, sorted(key_names))

    def test_cancel_editing_key_value(self):
        """
        Scenario: Test that advanced settings does not save the key value, if cancel
        is clicked from notification bar
            Given a staff logs in to studio
            When this user goes to advanced settings page and enters and new course name
                Then he clicks 'cancel' buttin when asked to save changes
            When this user reloads the page
                And then he does not see any change in the original course name
        """

        original_course_display_name = self.advanced_settings.get(self.course_name_key)
        new_course_name = 'New Course Name'
        type_in_codemirror(self.advanced_settings, 16, new_course_name)
        self.advanced_settings.cancel()
        self.advanced_settings.refresh_and_wait_for_load()
        self.assertNotEqual(
            original_course_display_name,
            new_course_name,
            (
                'original course name:{} can not not be equal to unsaved course name {}'.format(
                    original_course_display_name,
                    new_course_name
                )
            )
        )
        self.assertEqual(
            self.advanced_settings.get(self.course_name_key),
            original_course_display_name,
            (
                'course name from the page should be same as original_course_display_name:{}'.format(
                    original_course_display_name
                )
            )
        )

    def test_editing_key_value(self):
        """
        Scenario: Test that advanced settings saves the key value, if save button
        is clicked from notification bar after the editing
            Given a staff logs in to studio
            When this user goes to advanced settings page and enters a new course name
                And he clicks 'save' button from the notification bar
                Then he is able to see the updated course name
        """
        new_course_name = ''.join(random.choice(string.ascii_uppercase) for _ in range(10))
        self.advanced_settings.set(self.course_name_key, new_course_name)
        self.assertEqual(
            self.advanced_settings.get(self.course_name_key),
            '"{}"'.format(new_course_name),
            (
                'course name from the page should be same as new_course_name:{}'.format(
                    new_course_name
                )
            )
        )

    def test_confirmation_is_shown_on_save(self):
        """
        Scenario: Test that advanced settings shows confirmation after editing a field successfully
            Given a staff logs in to studio
            When this user goes to advanced settings page and  edits any value
                And he clicks 'save' button from the notification bar
                Then he is able to see the confirmation message
        """
        self.advanced_settings.set('Maximum Attempts', 5)
        confirmation_message = self.advanced_settings.confirmation_message
        self.assertEqual(
            confirmation_message,
            'Your policy changes have been saved.',
            'Settings must be saved successfully in order to have confirmation message'
        )

    def test_deprecated_settings_invisible_by_default(self):
        """
        Scenario: Test that advanced settings does not have deprecated settings by default
            Given a staff logs in to studio
            When this user goes to advanced settings page
                Then the user does not see the deprecated settings
                And sees 'Show Deprecated Settings' button
        """
        button_text = self.advanced_settings.deprecated_settings_button_text
        self.assertEqual(button_text, 'Show Deprecated Settings')
        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):
        """
        Test that advanced settings don't save if there's a single wrong input,
        and that it shows the correct error message in the modal.
        """

        # Feed an integer value for String field.
        # .set method saves automatically after setting a value
        course_display_name = self.advanced_settings.get('Course Display Name')
        self.advanced_settings.set('Course Display Name', 1)
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        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_multiple_validation_errors(self):
        """
        Test that advanced settings don't save with multiple wrong inputs
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        self.check_modal_shows_correct_contents(self.type_fields)
        self.advanced_settings.refresh_and_wait_for_load()

        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key),
                val,
                'Wrong input for Advanced Settings Fields must not change its value'
            )

    def test_undo_changes(self):
        """
        Test that undo changes button in the modal resets all settings changes
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()

        # Let modal popup
        self.advanced_settings.wait_for_modal_load()

        # Click Undo Changes button
        self.advanced_settings.undo_changes_via_modal()

        # Check that changes are undone
        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key),
                val,
                'Undoing Should revert back to original value'
            )

    def test_manual_change(self):
        """
        Test that manual changes button in the modal keeps settings unchanged
        """
        inputs = {"Course Display Name": 1,
                  "Advanced Module List": 1,
                  "Discussion Topic Mapping": 1,
                  "Maximum Attempts": '"string"',
                  "Course Announcement Date": '"string"',
                  }

        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()
        self.advanced_settings.trigger_manual_changes()

        # Check that the validation modal went away.
        self.assertFalse(self.advanced_settings.is_validation_modal_present())

        # Iterate through the wrong values and make sure they're still displayed
        for key, val in inputs.iteritems():
            self.assertEquals(
                str(self.advanced_settings.get(key)),
                str(val),
                'manual change should keep: ' + str(val) + ', but is: ' + str(self.advanced_settings.get(key))
            )

    def check_modal_shows_correct_contents(self, wrong_settings_list):
        """
        Helper function that checks if the validation modal contains correct
        error messages.
        """
        # Check presence of modal
        self.assertTrue(self.advanced_settings.is_validation_modal_present())

        # List of wrong settings item & what is presented in the modal should be the same
        error_item_names = self.advanced_settings.get_error_item_names()
        self.assertEqual(set(wrong_settings_list), set(error_item_names))

        error_item_messages = self.advanced_settings.get_error_item_messages()
        self.assertEqual(len(error_item_names), len(error_item_messages))

    def get_settings_fields_of_each_type(self):
        """
        Get one of each field type:
           - String: Course Display Name
           - List: Advanced Module List
           - Dict: Discussion Topic Mapping
           - Integer: Maximum Attempts
           - Date: Course Announcement Date
        """
        return {
            "Course Display Name": self.advanced_settings.get('Course Display Name'),
            "Advanced Module List": self.advanced_settings.get('Advanced Module List'),
            "Discussion Topic Mapping": self.advanced_settings.get('Discussion Topic Mapping'),
            "Maximum Attempts": self.advanced_settings.get('Maximum Attempts'),
            "Course Announcement Date": self.advanced_settings.get('Course Announcement Date'),
        }

    def set_wrong_inputs_to_fields(self):
        """
        Set wrong values for the chosen fields
        """
        self.advanced_settings.set_values(
            {
                "Course Display Name": 1,
                "Advanced Module List": 1,
                "Discussion Topic Mapping": 1,
                "Maximum Attempts": '"string"',
                "Course Announcement Date": '"string"',
            }
        )

    def test_only_expected_fields_are_displayed(self):
        """
        Scenario: The Advanced Settings screen displays settings/fields not specifically hidden from
        view by a developer.
        Given I have a set of CourseMetadata fields defined for the course
        When I view the Advanced Settings screen for the course
        The total number of fields displayed matches the number I expect
        And the actual fields displayed match the fields I expect to see
        """
        expected_fields = self.advanced_settings.expected_settings_names
        displayed_fields = self.advanced_settings.displayed_settings_names
        self.assertEquals(set(displayed_fields), set(expected_fields))
Exemplo n.º 3
0
class CertificatesTest(StudioCourseTest):
    """
    Tests for settings/certificates Page.
    """
    shard = 22

    def setUp(self):  # pylint: disable=arguments-differ
        super(CertificatesTest, self).setUp(is_staff=True, test_xss=False)
        self.certificates_page = CertificatesPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        self.advanced_settings_page = AdvancedSettingsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        self.course_advanced_settings = dict()

        # Add a verified mode to the course
        ModeCreationPage(
            self.browser, self.course_id, mode_slug=u'verified', mode_display_name=u'Verified Certificate',
            min_price=10, suggested_prices='10,20'
        ).visit()

    def make_signatory_data(self, prefix='First'):
        """
        Makes signatory dict which can be used in the tests to create certificates
        """
        return {
            'name': '{prefix} Signatory Name'.format(prefix=prefix),
            'title': '{prefix} Signatory Title'.format(prefix=prefix),
            'organization': '{prefix} Signatory Organization'.format(prefix=prefix),
        }

    def create_and_verify_certificate(self, course_title_override, existing_certs, signatories):
        """
        Creates a new certificate and verifies that it was properly created.
        """
        self.assertEqual(existing_certs, len(self.certificates_page.certificates))
        if existing_certs == 0:
            self.certificates_page.wait_for_first_certificate_button()
            self.certificates_page.click_first_certificate_button()
        else:
            self.certificates_page.wait_for_add_certificate_button()
            self.certificates_page.click_add_certificate_button()

        certificate = self.certificates_page.certificates[existing_certs]

        # Set the certificate properties
        certificate.course_title = course_title_override

        # add signatories
        added_signatories = 0
        for idx, signatory in enumerate(signatories):
            certificate.signatories[idx].name = signatory['name']
            certificate.signatories[idx].title = signatory['title']
            certificate.signatories[idx].organization = signatory['organization']
            certificate.signatories[idx].upload_signature_image('Signature-{}.png'.format(idx))

            added_signatories += 1
            if len(signatories) > added_signatories:
                certificate.click_add_signatory_button()

        # Save the certificate
        self.assertEqual(certificate.get_text('.action-primary'), "Create")
        certificate.click_create_certificate_button()
        self.assertIn(course_title_override, certificate.course_title)
        return certificate

    def test_no_certificates_by_default(self):
        """
        Scenario: Ensure that message telling me to create a new certificate is
            shown when no certificate exist.
        Given I have a course without certificates
        When I go to the Certificates page in Studio
        Then I see "You have not created any certificates yet." message and
        a link with text "Set up your certificate"
        """
        self.certificates_page.visit()
        self.assertTrue(self.certificates_page.no_certificates_message_shown)
        self.assertIn(
            "You have not created any certificates yet.",
            self.certificates_page.no_certificates_message_text
        )
        self.assertIn(
            "Set up your certificate",
            self.certificates_page.new_certificate_link_text
        )

    def test_can_create_and_edit_certficate(self):
        """
        Scenario: Ensure that the certificates can be created and edited correctly.
        Given I have a course without certificates
        When I click button 'Add your first Certificate'
        And I set new the course title override and signatory and click the button 'Create'
        Then I see the new certificate is added and has correct data
        When I edit the  certificate
        And I change the name and click the button 'Save'
        Then I see the certificate is saved successfully and has the new name
        """
        self.certificates_page.visit()
        self.certificates_page.wait_for_first_certificate_button()
        certificate = self.create_and_verify_certificate(
            "Course Title Override",
            0,
            [self.make_signatory_data('first'), self.make_signatory_data('second')]
        )

        # Edit the certificate
        certificate.click_edit_certificate_button()
        certificate.course_title = "Updated Course Title Override 2"
        self.assertEqual(certificate.get_text('.action-primary'), "Save")
        certificate.click_save_certificate_button()

        self.assertIn("Updated Course Title Override 2", certificate.course_title)

    def test_can_delete_certificate(self):
        """
        Scenario: Ensure that the user can delete certificate.
        Given I have a course with 1 certificate
        And I go to the Certificates page
        When I delete the Certificate with name "New Certificate"
        Then I see that there is no certificate
        When I refresh the page
        Then I see that the certificate has been deleted
        """
        self.certificates_page.visit()
        certificate = self.create_and_verify_certificate(
            "Course Title Override",
            0,
            [self.make_signatory_data('first'), self.make_signatory_data('second')]
        )

        certificate.wait_for_certificate_delete_button()

        self.assertEqual(len(self.certificates_page.certificates), 1)

        # Delete the certificate we just created
        certificate.click_delete_certificate_button()
        self.certificates_page.click_confirmation_prompt_primary_button()

        # Reload the page and confirm there are no certificates
        self.certificates_page.visit()
        self.assertEqual(len(self.certificates_page.certificates), 0)

    @skip_if_browser('chrome')  # TODO Need to fix this for chrome browser
    def test_can_create_and_edit_signatories_of_certficate(self):
        """
        Scenario: Ensure that the certificates can be created with signatories and edited correctly.
        Given I have a course without certificates
        When I click button 'Add your first Certificate'
        And I set new the course title override and signatory and click the button 'Create'
        Then I see the new certificate is added and has one signatory inside it
        When I click 'Edit' button of signatory panel
        And I set the name and click the button 'Save' icon
        Then I see the signatory name updated with newly set name
        When I refresh the certificates page
        Then I can see course has one certificate with new signatory name
        When I click 'Edit' button of signatory panel
        And click on 'Close' button
        Then I can see no change in signatory detail
        """
        self.certificates_page.visit()
        certificate = self.create_and_verify_certificate(
            "Course Title Override",
            0,
            [self.make_signatory_data('first')]
        )
        self.assertEqual(len(self.certificates_page.certificates), 1)
        # Edit the signatory in certificate
        signatory = certificate.signatories[0]
        signatory.edit()

        signatory.name = 'Updated signatory name'
        signatory.title = 'Update signatory title'
        signatory.organization = 'Updated signatory organization'
        signatory.save()

        self.assertEqual(len(self.certificates_page.certificates), 1)

        #Refreshing the page, So page have the updated certificate object.
        self.certificates_page.refresh()
        self.certificates_page.wait_for_page()
        signatory = self.certificates_page.certificates[0].signatories[0]
        self.assertIn("Updated signatory name", signatory.name)
        self.assertIn("Update signatory title", signatory.title)
        self.assertIn("Updated signatory organization", signatory.organization)

        signatory.edit()
        signatory.close()

        self.assertIn("Updated signatory name", signatory.name)

    def test_can_cancel_creation_of_certificate(self):
        """
        Scenario: Ensure that creation of a certificate can be canceled correctly.
        Given I have a course without certificates
        When I click button 'Add your first Certificate'
        And I set name of certificate and click the button 'Cancel'
        Then I see that there is no certificates in the course
        """
        self.certificates_page.visit()
        self.certificates_page.click_first_certificate_button()
        certificate = self.certificates_page.certificates[0]
        certificate.course_title = "Title Override"
        certificate.click_cancel_edit_certificate()
        self.assertEqual(len(self.certificates_page.certificates), 0)

    def test_line_breaks_in_signatory_title(self):
        """
        Scenario: Ensure that line breaks are properly reflected in certificate

        Given I have a certificate with signatories
        When I add signatory title with new line character
        Then I see line break in certificate title
        """
        self.certificates_page.visit()
        certificate = self.create_and_verify_certificate(
            "Course Title Override",
            0,
            [
                {
                    'name': 'Signatory Name',
                    'title': 'Signatory title with new line character \n',
                    'organization': 'Signatory Organization',
                }
            ]
        )

        certificate.wait_for_certificate_delete_button()

        # Make sure certificate is created
        self.assertEqual(len(self.certificates_page.certificates), 1)

        signatory_title = self.certificates_page.get_first_signatory_title()
        self.assertNotEqual([], re.findall(r'<br\s*/?>', signatory_title))

    def test_course_number_in_certificate_details_view(self):
        """
        Scenario: Ensure that Course Number is displayed in certificate details view

        Given I have a certificate
        When I visit certificate details page on studio
        Then I see Course Number next to Course Name
        """
        self.certificates_page.visit()
        certificate = self.create_and_verify_certificate(
            "Course Title Override",
            0,
            [self.make_signatory_data('first')]
        )

        certificate.wait_for_certificate_delete_button()

        # Make sure certificate is created
        self.assertEqual(len(self.certificates_page.certificates), 1)
        course_number = self.certificates_page.get_course_number()
        self.assertEqual(self.course_info['number'], course_number)

    def test_course_number_override_in_certificate_details_view(self):
        """
        Scenario: Ensure that Course Number Override is displayed in certificate details view

        Given I have a certificate
        When I visit certificate details page on studio then course number override should be hidden.
        Then I visit the course advance settings page and set the value for course override number.
        Then I see Course Number Override next to Course Name in certificate settings page.
        """

        self.course_advanced_settings.update(
            {'Course Number Display String': 'Course Number Override String'}
        )

        self.certificates_page.visit()
        certificate = self.create_and_verify_certificate(
            "Course Title Override",
            0,
            [self.make_signatory_data('first')]
        )
        self.assertFalse(self.certificates_page.course_number_override().present)
        certificate.wait_for_certificate_delete_button()

        # Make sure certificate is created
        self.assertEqual(len(self.certificates_page.certificates), 1)

        # set up course number override in Advanced Settings Page
        self.advanced_settings_page.visit()
        self.advanced_settings_page.set_values(self.course_advanced_settings)
        self.advanced_settings_page.wait_for_ajax()

        self.certificates_page.visit()
        course_number_override = self.certificates_page.get_course_number_override()
        self.assertEqual(self.course_advanced_settings['Course Number Display String'], course_number_override)
        self.assertTrue(self.certificates_page.course_number_override().present)
Exemplo n.º 4
0
class AdvancedSettingsValidationTest(StudioCourseTest):
    """
    Tests for validation feature in Studio's advanced settings tab
    """
    course_name_key = 'Course Display Name'
    course_name_value = 'Test Name'

    def setUp(self):
        super(AdvancedSettingsValidationTest, self).setUp()
        self.advanced_settings = AdvancedSettingsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.type_fields = ['Course Display Name', 'Advanced Module List', 'Discussion Topic Mapping',
                            'Maximum Attempts', 'Course Announcement Date']

        # Before every test, make sure to visit the page first
        self.advanced_settings.visit()

    def test_course_author_sees_default_advanced_settings(self):
        """
        Scenario: Test that advanced settings have the default settings
            Given a staff logs in to studio
            When this user goes to advanced settings page
                Then this user sees 'Allow Anonymous Discussion Posts' as true
                And 'Enable Timed Exams' as false
                And 'Maximum Attempts' as null
        """
        anonymous_discussion_setting = self.advanced_settings.get('Allow Anonymous Discussion Posts')
        timed_exam_settings = self.advanced_settings.get('Enable Timed Exams')
        max_attempts = self.advanced_settings.get('Maximum Attempts')
        page_default_settings = [
            anonymous_discussion_setting,
            timed_exam_settings,
            max_attempts
        ]
        default_anonymous_discussion_setting = 'true'
        default_timed_exam_settings = 'false'
        default_max_attempts = 'null'
        expected_default_settings = [
            default_anonymous_discussion_setting,
            default_timed_exam_settings,
            default_max_attempts
        ]
        self.assertEqual(
            page_default_settings,
            expected_default_settings
        )

    def test_keys_appear_alphabetically(self):
        """
        Scenario: Test that advanced settings have all the keys in alphabetic order
            Given a staff logs in to studio
            When this user goes to advanced settings page
                Then he sees all the advanced setting keys in alphabetic order
        """

        key_names = self.advanced_settings.key_names
        self.assertEqual(key_names, sorted(key_names))

    def test_cancel_editing_key_value(self):
        """
        Scenario: Test that advanced settings does not save the key value, if cancel
        is clicked from notification bar
            Given a staff logs in to studio
            When this user goes to advanced settings page and enters and new course name
                Then he clicks 'cancel' buttin when asked to save changes
            When this user reloads the page
                And then he does not see any change in the original course name
        """

        original_course_display_name = self.advanced_settings.get(self.course_name_key)
        new_course_name = 'New Course Name'
        type_in_codemirror(self.advanced_settings, 16, new_course_name)
        self.advanced_settings.cancel()
        self.advanced_settings.refresh_and_wait_for_load()
        self.assertNotEqual(
            original_course_display_name,
            new_course_name,
            (
                'original course name:{} can not not be equal to unsaved course name {}'.format(
                    original_course_display_name,
                    new_course_name
                )
            )
        )
        self.assertEqual(
            self.advanced_settings.get(self.course_name_key),
            original_course_display_name,
            (
                'course name from the page should be same as original_course_display_name:{}'.format(
                    original_course_display_name
                )
            )
        )

    def test_editing_key_value(self):
        """
        Scenario: Test that advanced settings saves the key value, if save button
        is clicked from notification bar after the editing
            Given a staff logs in to studio
            When this user goes to advanced settings page and enters a new course name
                And he clicks 'save' button from the notification bar
                Then he is able to see the updated course name
        """
        new_course_name = ''.join(random.choice(string.ascii_uppercase) for _ in range(10))
        self.advanced_settings.set(self.course_name_key, new_course_name)
        self.assertEqual(
            self.advanced_settings.get(self.course_name_key),
            '"{}"'.format(new_course_name),
            (
                'course name from the page should be same as new_course_name:{}'.format(
                    new_course_name
                )
            )
        )

    def test_confirmation_is_shown_on_save(self):
        """
        Scenario: Test that advanced settings shows confirmation after editing a field successfully
            Given a staff logs in to studio
            When this user goes to advanced settings page and  edits any value
                And he clicks 'save' button from the notification bar
                Then he is able to see the confirmation message
        """
        self.advanced_settings.set('Maximum Attempts', 5)
        confirmation_message = self.advanced_settings.confirmation_message
        self.assertEqual(
            confirmation_message,
            'Your policy changes have been saved.',
            'Settings must be saved successfully in order to have confirmation message'
        )

    def test_deprecated_settings_invisible_by_default(self):
        """
        Scenario: Test that advanced settings does not have deprecated settings by default
            Given a staff logs in to studio
            When this user goes to advanced settings page
                Then the user does not see the deprecated settings
                And sees 'Show Deprecated Settings' button
        """
        button_text = self.advanced_settings.deprecated_settings_button_text
        self.assertEqual(button_text, 'Show Deprecated Settings')
        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):
        """
        Test that advanced settings don't save if there's a single wrong input,
        and that it shows the correct error message in the modal.
        """

        # Feed an integer value for String field.
        # .set method saves automatically after setting a value
        course_display_name = self.advanced_settings.get('Course Display Name')
        self.advanced_settings.set('Course Display Name', 1)
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        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_multiple_validation_errors(self):
        """
        Test that advanced settings don't save with multiple wrong inputs
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        self.check_modal_shows_correct_contents(self.type_fields)
        self.advanced_settings.refresh_and_wait_for_load()

        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key),
                val,
                'Wrong input for Advanced Settings Fields must not change its value'
            )

    def test_undo_changes(self):
        """
        Test that undo changes button in the modal resets all settings changes
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()

        # Let modal popup
        self.advanced_settings.wait_for_modal_load()

        # Click Undo Changes button
        self.advanced_settings.undo_changes_via_modal()

        # Check that changes are undone
        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key),
                val,
                'Undoing Should revert back to original value'
            )

    def test_manual_change(self):
        """
        Test that manual changes button in the modal keeps settings unchanged
        """
        inputs = {"Course Display Name": 1,
                  "Advanced Module List": 1,
                  "Discussion Topic Mapping": 1,
                  "Maximum Attempts": '"string"',
                  "Course Announcement Date": '"string"',
                  }

        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()
        self.advanced_settings.trigger_manual_changes()

        # Check that the validation modal went away.
        self.assertFalse(self.advanced_settings.is_validation_modal_present())

        # Iterate through the wrong values and make sure they're still displayed
        for key, val in inputs.iteritems():
            self.assertEquals(
                str(self.advanced_settings.get(key)),
                str(val),
                'manual change should keep: ' + str(val) + ', but is: ' + str(self.advanced_settings.get(key))
            )

    def check_modal_shows_correct_contents(self, wrong_settings_list):
        """
        Helper function that checks if the validation modal contains correct
        error messages.
        """
        # Check presence of modal
        self.assertTrue(self.advanced_settings.is_validation_modal_present())

        # List of wrong settings item & what is presented in the modal should be the same
        error_item_names = self.advanced_settings.get_error_item_names()
        self.assertEqual(set(wrong_settings_list), set(error_item_names))

        error_item_messages = self.advanced_settings.get_error_item_messages()
        self.assertEqual(len(error_item_names), len(error_item_messages))

    def get_settings_fields_of_each_type(self):
        """
        Get one of each field type:
           - String: Course Display Name
           - List: Advanced Module List
           - Dict: Discussion Topic Mapping
           - Integer: Maximum Attempts
           - Date: Course Announcement Date
        """
        return {
            "Course Display Name": self.advanced_settings.get('Course Display Name'),
            "Advanced Module List": self.advanced_settings.get('Advanced Module List'),
            "Discussion Topic Mapping": self.advanced_settings.get('Discussion Topic Mapping'),
            "Maximum Attempts": self.advanced_settings.get('Maximum Attempts'),
            "Course Announcement Date": self.advanced_settings.get('Course Announcement Date'),
        }

    def set_wrong_inputs_to_fields(self):
        """
        Set wrong values for the chosen fields
        """
        self.advanced_settings.set_values(
            {
                "Course Display Name": 1,
                "Advanced Module List": 1,
                "Discussion Topic Mapping": 1,
                "Maximum Attempts": '"string"',
                "Course Announcement Date": '"string"',
            }
        )

    def test_only_expected_fields_are_displayed(self):
        """
        Scenario: The Advanced Settings screen displays settings/fields not specifically hidden from
        view by a developer.
        Given I have a set of CourseMetadata fields defined for the course
        When I view the Advanced Settings screen for the course
        The total number of fields displayed matches the number I expect
        And the actual fields displayed match the fields I expect to see
        """
        expected_fields = self.advanced_settings.expected_settings_names
        displayed_fields = self.advanced_settings.displayed_settings_names
        self.assertEquals(set(displayed_fields), set(expected_fields))
Exemplo n.º 5
0
class AdvancedSettingsValidationTest(StudioCourseTest):
    """
    Tests for validation feature in Studio's advanced settings tab
    """
    def setUp(self):
        super(AdvancedSettingsValidationTest, self).setUp()
        self.advanced_settings = AdvancedSettingsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.type_fields = [
            'Course Display Name', 'Advanced Module List',
            'Discussion Topic Mapping', 'Maximum Attempts',
            'Course Announcement Date'
        ]

        # Before every test, make sure to visit the page first
        self.advanced_settings.visit()

    def test_modal_shows_one_validation_error(self):
        """
        Test that advanced settings don't save if there's a single wrong input,
        and that it shows the correct error message in the modal.
        """

        # Feed an integer value for String field.
        # .set method saves automatically after setting a value
        course_display_name = self.advanced_settings.get('Course Display Name')
        self.advanced_settings.set('Course Display Name', 1)
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        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_multiple_validation_errors(self):
        """
        Test that advanced settings don't save with multiple wrong inputs
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()

        # Test Modal
        self.check_modal_shows_correct_contents(self.type_fields)
        self.advanced_settings.refresh_and_wait_for_load()

        for key, val in original_values_map.iteritems():
            self.assertEquals(
                self.advanced_settings.get(key), val,
                'Wrong input for Advanced Settings Fields must not change its value'
            )

    def test_undo_changes(self):
        """
        Test that undo changes button in the modal resets all settings changes
        """

        # Save original values and feed wrong inputs
        original_values_map = self.get_settings_fields_of_each_type()
        self.set_wrong_inputs_to_fields()

        # Let modal popup
        self.advanced_settings.wait_for_modal_load()

        # Click Undo Changes button
        self.advanced_settings.undo_changes_via_modal()

        # Check that changes are undone
        for key, val in original_values_map.iteritems():
            self.assertEquals(self.advanced_settings.get(key), val,
                              'Undoing Should revert back to original value')

    def test_manual_change(self):
        """
        Test that manual changes button in the modal keeps settings unchanged
        """
        inputs = {
            "Course Display Name": 1,
            "Advanced Module List": 1,
            "Discussion Topic Mapping": 1,
            "Maximum Attempts": '"string"',
            "Course Announcement Date": '"string"',
        }

        self.set_wrong_inputs_to_fields()
        self.advanced_settings.wait_for_modal_load()
        self.advanced_settings.trigger_manual_changes()

        # Check that the validation modal went away.
        self.assertFalse(self.advanced_settings.is_validation_modal_present())

        # Iterate through the wrong values and make sure they're still displayed
        for key, val in inputs.iteritems():
            self.assertEquals(
                str(self.advanced_settings.get(key)), str(val),
                'manual change should keep: ' + str(val) + ', but is: ' +
                str(self.advanced_settings.get(key)))

    def check_modal_shows_correct_contents(self, wrong_settings_list):
        """
        Helper function that checks if the validation modal contains correct
        error messages.
        """
        # Check presence of modal
        self.assertTrue(self.advanced_settings.is_validation_modal_present())

        # List of wrong settings item & what is presented in the modal should be the same
        error_item_names = self.advanced_settings.get_error_item_names()
        self.assertEqual(set(wrong_settings_list), set(error_item_names))

        error_item_messages = self.advanced_settings.get_error_item_messages()
        self.assertEqual(len(error_item_names), len(error_item_messages))

    def get_settings_fields_of_each_type(self):
        """
        Get one of each field type:
           - String: Course Display Name
           - List: Advanced Module List
           - Dict: Discussion Topic Mapping
           - Integer: Maximum Attempts
           - Date: Course Announcement Date
        """
        return {
            "Course Display Name":
            self.advanced_settings.get('Course Display Name'),
            "Advanced Module List":
            self.advanced_settings.get('Advanced Module List'),
            "Discussion Topic Mapping":
            self.advanced_settings.get('Discussion Topic Mapping'),
            "Maximum Attempts":
            self.advanced_settings.get('Maximum Attempts'),
            "Course Announcement Date":
            self.advanced_settings.get('Course Announcement Date'),
        }

    def set_wrong_inputs_to_fields(self):
        """
        Set wrong values for the chosen fields
        """
        self.advanced_settings.set_values({
            "Course Display Name":
            1,
            "Advanced Module List":
            1,
            "Discussion Topic Mapping":
            1,
            "Maximum Attempts":
            '"string"',
            "Course Announcement Date":
            '"string"',
        })

    def test_only_expected_fields_are_displayed(self):
        """
        Scenario: The Advanced Settings screen displays settings/fields not specifically hidden from
        view by a developer.
        Given I have a set of CourseMetadata fields defined for the course
        When I view the Advanced Settings screen for the course
        The total number of fields displayed matches the number I expect
        And the actual fields displayed match the fields I expect to see
        """
        expected_fields = self.advanced_settings.expected_settings_names
        displayed_fields = self.advanced_settings.displayed_settings_names
        self.assertEquals(set(displayed_fields), set(expected_fields))