def test_no_content_groups(self):
        """
        Scenario: if the course has no content groups defined (user_partitions of type cohort),
        the settings in the cohort management tab reflect this

        Given I have a course with a cohort defined but no content groups
        When I view the cohort in the instructor dashboard and select settings
        Then the cohort is not linked to a content group
        And there is text stating that no content groups are defined
        And I cannot select the radio button to enable content group association
        And there is a link I can select to open Group settings in Studio
        """
        self.cohort_management_page.select_cohort(self.manual_cohort_name)
        self.assertIsNone(
            self.cohort_management_page.get_cohort_associated_content_group())
        self.assertEqual(
            "Warning:\nNo content groups exist. Create a content group",
            self.cohort_management_page.
            get_cohort_related_content_group_message())
        self.assertFalse(
            self.cohort_management_page.select_content_group_radio_button())
        self.cohort_management_page.select_studio_group_settings()
        group_settings_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])
        group_settings_page.wait_for_page()
Beispiel #2
0
 def setUp(self):  # pylint: disable=arguments-differ
     super(GroupExperimentConfigurationHelpTest, self).setUp()
     self.group_configuration_page = GroupConfigurationsPage(
         self.browser, self.course_info['org'], self.course_info['number'],
         self.course_info['run'])
     # self.create_poorly_configured_split_instance()
     self.group_configuration_page.visit()
    def test_no_content_groups(self):
        """
        Scenario: if the course has no content groups defined (user_partitions of type cohort),
        the settings in the cohort management tab reflect this

        Given I have a course with a cohort defined but no content groups
        When I view the cohort in the instructor dashboard and select settings
        Then the cohort is not linked to a content group
        And there is text stating that no content groups are defined
        And I cannot select the radio button to enable content group association
        And there is a link I can select to open Group settings in Studio
        """
        self.cohort_management_page.select_cohort(self.manual_cohort_name)
        self.assertIsNone(self.cohort_management_page.get_cohort_associated_content_group())
        self.assertEqual(
            "Warning:\nNo content groups exist. Create a content group",
            self.cohort_management_page.get_cohort_related_content_group_message()
        )
        self.assertFalse(self.cohort_management_page.select_content_group_radio_button())
        self.cohort_management_page.select_studio_group_settings()
        group_settings_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        group_settings_page.wait_for_page()
Beispiel #4
0
    def setUp(self, is_staff=False, test_xss=True):
        super(CourseGroupConfigurationHelpTest, self).setUp()

        self.course_group_configuration_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.course_group_configuration_page.visit()
 def setUp(self):
     super(GroupConfigurationsNoSplitTest, self).setUp()
     self.group_configurations_page = GroupConfigurationsPage(
         self.browser,
         self.course_info['org'],
         self.course_info['number'],
         self.course_info['run']
     )
class CourseGroupConfigurationHelpTest(StudioCourseTest):
    """
    Tests help links on course Group Configurations settings page
    """
    def setUp(self, is_staff=False, test_xss=True):
        super(CourseGroupConfigurationHelpTest, self).setUp()

        self.course_group_configuration_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.course_group_configuration_page.visit()

    @skip(
        "Disabled as edx.org help links are now different than Open edX (@catong can advise)"
    )
    def test_course_group_conf_nav_help(self):
        """
        Scenario: Help link in navigation bar is working on
                  Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Help' in the navigation bar
        Then Help link should open.
        And help url should be correct
        """
        expected_url = _get_expected_documentation_url('/index.html')

        # Assert that help link is correct.
        assert_nav_help_link(
            test=self,
            page=self.course_group_configuration_page,
            href=expected_url,
        )

    @skip(
        "Disabled as edx.org help links are now different than Open edX (@catong can advise)"
    )
    def test_course_group_conf_content_group_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'content group' is working
                  on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should be correct
        """
        expected_url = _get_expected_documentation_url(
            '/course_features/cohorts/cohorted_courseware.html')

        # Assert that help link is correct.
        assert_side_bar_help_link(test=self,
                                  page=self.course_group_configuration_page,
                                  href=expected_url,
                                  help_text='Learn More')
class CourseGroupConfigurationHelpTest(StudioCourseTest):
    """
    Tests help links on course Group Configurations settings page
    """
    def setUp(self, is_staff=False, test_xss=True):
        super(CourseGroupConfigurationHelpTest, self).setUp()

        self.course_group_configuration_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.course_group_configuration_page.visit()

    def test_course_group_conf_nav_help(self):
        """
        Scenario: Help link in navigation bar is working on
                  Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Help' in the navigation bar
        Then Help link should open.
        And help url should end with 'index.html'
        """
        href = 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/' \
               'en/open-release-ficus.master/index.html'

        # Assert that help link is correct.
        assert_nav_help_link(
            test=self,
            page=self.course_group_configuration_page,
            href=href
        )

    def test_course_group_conf_content_group_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'content group' is working
                  on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should end with 'course_features/cohorts/cohorted_courseware.html'
        """
        href = 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/' \
               'en/open-release-ficus.master/course_features/cohorts/cohorted_courseware.html'

        # Assert that help link is correct.
        assert_side_bar_help_link(
            test=self,
            page=self.course_group_configuration_page,
            href=href,
            help_text='Learn More'
        )
    def setUp(self):
        super(ContentGroupConfigurationTest, self).setUp()
        self.group_configurations_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.outline_page = CourseOutlinePage(self.browser,
                                              self.course_info['org'],
                                              self.course_info['number'],
                                              self.course_info['run'])
Beispiel #9
0
class CourseGroupConfigurationHelpTest(StudioCourseTest):
    """
    Tests help links on course Group Configurations settings page
    """
    def setUp(self, is_staff=False, test_xss=True):
        super(CourseGroupConfigurationHelpTest, self).setUp()

        self.course_group_configuration_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.course_group_configuration_page.visit()

    def test_course_group_conf_nav_help(self):
        """
        Scenario: Help link in navigation bar is working on
                  Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Help' in the navigation bar
        Then Help link should open.
        And help url should be correct
        """
        expected_url = _get_expected_documentation_url('/index.html')

        # Assert that help link is correct.
        assert_nav_help_link(
            test=self,
            page=self.course_group_configuration_page,
            href=expected_url,
        )

    def test_course_group_conf_content_group_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'content group' is working
                  on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should be correct
        """
        expected_url = _get_expected_documentation_url('/course_features/cohorts/cohorted_courseware.html')

        # Assert that help link is correct.
        assert_side_bar_help_link(
            test=self,
            page=self.course_group_configuration_page,
            href=expected_url,
            help_text='Learn More'
        )
 def test_one_course_mode(self):
     """
     The purpose of this test is to ensure that when there is 1 or fewer course modes
     the enrollment track section is not shown.
     """
     add_enrollment_course_modes(self.browser, self.course_id, ['audit'])
     group_configurations_page = GroupConfigurationsPage(
         self.browser, self.course_info['org'], self.course_info['number'],
         self.course_info['run'])
     group_configurations_page.visit()
     self.assertFalse(
         group_configurations_page.enrollment_track_section_present)
     groups = group_configurations_page.get_enrollment_groups()
     self.assertEqual(len(groups), 0)
Beispiel #11
0
class GroupExperimentConfigurationHelpTest(ContainerBase):
    """
    Tests help links on course Group Configurations settings page

    It is related to Experiment Group Configurations on the page.
    """
    def setUp(self):  # pylint: disable=arguments-differ
        super(GroupExperimentConfigurationHelpTest, self).setUp()
        self.group_configuration_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        # self.create_poorly_configured_split_instance()
        self.group_configuration_page.visit()

    def populate_course_fixture(self, course_fixture):
        """
        Populates the course fixture.

        We are modifying 'advanced_modules' setting of the
        course.
        """
        course_fixture.add_advanced_settings(
            {u"advanced_modules": {"value": ["split_test"]}}
        )

    def test_course_group_configuration_experiment_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'Experiment Group Configurations'
                  is working on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should be correct
        """
        expected_url = _get_expected_documentation_url(
            '/course_features/content_experiments/content_experiments_configure.html'
            '#set-up-group-configurations-in-edx-studio'
        )

        # Assert that help link is correct.
        assert_side_bar_help_link(
            test=self,
            page=self.group_configuration_page,
            href=expected_url,
            help_text='Learn More',
        )
Beispiel #12
0
class GroupExperimentConfigurationHelpTest(ContainerBase):
    """
    Tests help links on course Group Configurations settings page

    It is related to Experiment Group Configurations on the page.
    """
    def setUp(self):  # pylint: disable=arguments-differ
        super(GroupExperimentConfigurationHelpTest, self).setUp()
        self.group_configuration_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        # self.create_poorly_configured_split_instance()
        self.group_configuration_page.visit()

    def populate_course_fixture(self, course_fixture):
        """
        Populates the course fixture.

        We are modifying 'advanced_modules' setting of the
        course.
        """
        course_fixture.add_advanced_settings(
            {u"advanced_modules": {"value": ["split_test"]}}
        )

    def test_course_group_configuration_experiment_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'Experiment Group Configurations'
                  is working on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should be correct
        """
        expected_url = _get_expected_documentation_url(
            '/course_features/content_experiments/content_experiments_configure.html'
            '#set-up-group-configurations-in-edx-studio'
        )

        # Assert that help link is correct.
        assert_side_bar_help_link(
            test=self,
            page=self.group_configuration_page,
            href=expected_url,
            help_text='Learn More',
        )
Beispiel #13
0
class CourseGroupConfigurationHelpTest(StudioCourseTest):
    """
    Tests help links on course Group Configurations settings page
    """
    def setUp(self, is_staff=False, test_xss=True):
        super(CourseGroupConfigurationHelpTest, self).setUp()

        self.course_group_configuration_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.course_group_configuration_page.visit()

    def test_course_group_conf_nav_help(self):
        """
        Scenario: Help link in navigation bar is working on
                  Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Help' in the navigation bar
        Then Help link should open.
        And help url should end with 'index.html'
        """
        href = 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/' \
               'en/latest/index.html'

        # Assert that help link is correct.
        assert_nav_help_link(test=self,
                             page=self.course_group_configuration_page,
                             href=href)

    def test_course_group_conf_content_group_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'content group' is working
                  on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should end with 'course_features/cohorts/cohorted_courseware.html'
        """
        href = 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/' \
               'en/latest/course_features/cohorts/cohorted_courseware.html'

        # Assert that help link is correct.
        assert_side_bar_help_link(test=self,
                                  page=self.course_group_configuration_page,
                                  href=href,
                                  help_text='Learn More')
 def setUp(self):  # pylint: disable=arguments-differ
     super(GroupExperimentConfigurationHelpTest, self).setUp()
     self.group_configuration_page = GroupConfigurationsPage(
         self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"]
     )
     # self.create_poorly_configured_split_instance()
     self.group_configuration_page.visit()
 def test_one_course_mode(self):
     """
     The purpose of this test is to ensure that when there is 1 or fewer course modes
     the enrollment track section is not shown.
     """
     add_enrollment_course_modes(self.browser, self.course_id, ['audit'])
     group_configurations_page = GroupConfigurationsPage(
         self.browser,
         self.course_info['org'],
         self.course_info['number'],
         self.course_info['run']
     )
     group_configurations_page.visit()
     self.assertFalse(group_configurations_page.enrollment_track_section_present)
     groups = group_configurations_page.get_enrollment_groups()
     self.assertEqual(len(groups), 0)
    def setUp(self, is_staff=False, test_xss=True):
        super(CourseGroupConfigurationHelpTest, self).setUp()

        self.course_group_configuration_page = GroupConfigurationsPage(
            self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"]
        )

        self.course_group_configuration_page.visit()
 def setUp(self):
     super(GroupConfigurationsNoSplitTest, self).setUp()
     self.group_configurations_page = GroupConfigurationsPage(
         self.browser,
         self.course_info['org'],
         self.course_info['number'],
         self.course_info['run']
     )
Beispiel #18
0
class GroupConfigurationsNoSplitTest(StudioCourseTest):
    """
    Tests how the Group Configuration page should look when the split_test module is not enabled.
    """
    def setUp(self):
        super(GroupConfigurationsNoSplitTest, self).setUp()
        self.group_configurations_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

    def test_no_content_experiment_sections(self):
        """
        Scenario: if split_test module is not present in Advanced Settings, content experiment
           parts of the Group Configurations page are not shown.
        Given I have a course with split_test module not enabled
        Then when I go to the Group Configurations page there are no content experiment sections
        """
        self.group_configurations_page.visit()
        self.assertFalse(
            self.group_configurations_page.experiment_group_sections_present)
class GroupExperimentConfigurationHelpTest(ContainerBase):
    """
    Tests help links on course Group Configurations settings page

    It is related to Experiment Group Configurations on the page.
    """

    def setUp(self):  # pylint: disable=arguments-differ
        super(GroupExperimentConfigurationHelpTest, self).setUp()
        self.group_configuration_page = GroupConfigurationsPage(
            self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"]
        )
        # self.create_poorly_configured_split_instance()
        self.group_configuration_page.visit()

    def populate_course_fixture(self, course_fixture):
        """
        Populates the course fixture.

        We are modifying 'advanced_modules' setting of the
        course.
        """
        course_fixture.add_advanced_settings({u"advanced_modules": {"value": ["split_test"]}})

    def test_course_group_configuration_experiment_side_bar_help(self):
        """
        Scenario: Help link in side bar under the 'Experiment Group Configurations'
                  is working on Group Configurations settings page
        Given that I am on the Group Configurations settings page
        And I want help about the process
        And I click the 'Learn More' in the sidebar links
        Then Help link should open.
        And help url should end with
        'content_experiments_configure.html#set-up-group-configurations-in-edx-studio'
        """
        href = (
            "http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/course_features"
            "/content_experiments/content_experiments_configure.html#set-up-group-configurations-in-edx-studio"
        )
        # Assert that help link is correct.
        assert_side_bar_help_link(test=self, page=self.group_configuration_page, href=href, help_text="Learn More")
    def test_all_course_modes_present(self):
        """
        This test is meant to ensure that all the course modes show up as groups
        on the Group configuration page within the Enrollment Tracks section.
        It also checks to make sure that the edit buttons are not available.
        """
        add_enrollment_course_modes(self.browser, self.course_id, ['audit', 'verified'])
        group_configurations_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        group_configurations_page.visit()
        self.assertTrue(group_configurations_page.enrollment_track_section_present)

        # Make sure the edit buttons are not available.
        self.assertFalse(group_configurations_page.enrollment_track_edit_present)
        groups = group_configurations_page.get_enrollment_groups()
        for g in [self.audit_track, self.verified_track]:
            self.assertTrue(g in groups)
    def test_all_course_modes_present(self):
        """
        This test is meant to ensure that all the course modes show up as groups
        on the Group configuration page within the Enrollment Tracks section.
        It also checks to make sure that the edit buttons are not available.
        """
        add_enrollment_course_modes(self.browser, self.course_id, ['audit', 'verified'])
        group_configurations_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        group_configurations_page.visit()
        self.assertTrue(group_configurations_page.enrollment_track_section_present)

        # Make sure the edit buttons are not available.
        self.assertFalse(group_configurations_page.enrollment_track_edit_present)
        groups = group_configurations_page.get_enrollment_groups()
        for g in [self.audit_track, self.verified_track]:
            self.assertTrue(g in groups)
class GroupConfigurationsNoSplitTest(StudioCourseTest):
    """
    Tests how the Group Configuration page should look when the split_test module is not enabled.
    """
    def setUp(self):
        super(GroupConfigurationsNoSplitTest, self).setUp()
        self.group_configurations_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

    def test_no_content_experiment_sections(self):
        """
        Scenario: if split_test module is not present in Advanced Settings, content experiment
           parts of the Group Configurations page are not shown.
        Given I have a course with split_test module not enabled
        Then when I go to the Group Configurations page there are no content experiment sections
        """
        self.group_configurations_page.visit()
        self.assertFalse(self.group_configurations_page.experiment_group_sections_present)
    def setUp(self):
        super(GroupConfigurationsTest, self).setUp()
        self.page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
    def create_content_groups(self):
        """
        Creates two content groups in Studio Group Configurations Settings.
        """
        group_configurations_page = GroupConfigurationsPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])
        group_configurations_page.visit()

        group_configurations_page.create_first_content_group()
        config = group_configurations_page.content_groups[0]
        config.name = self.content_group_a
        config.save()

        group_configurations_page.add_content_group()
        config = group_configurations_page.content_groups[1]
        config.name = self.content_group_b
        config.save()
    def create_content_groups(self):
        """
        Creates two content groups in Studio Group Configurations Settings.
        """
        group_configurations_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        group_configurations_page.visit()

        group_configurations_page.create_first_content_group()
        config = group_configurations_page.content_groups[0]
        config.name = self.content_group_a
        config.save()

        group_configurations_page.add_content_group()
        config = group_configurations_page.content_groups[1]
        config.name = self.content_group_b
        config.save()
class ContentGroupConfigurationTest(StudioCourseTest):
    """
    Tests for content groups in the Group Configurations Page.
    There are tests for the experiment groups in test_studio_split_test.
    """
    def setUp(self):
        super(ContentGroupConfigurationTest, self).setUp()
        self.group_configurations_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

    def populate_course_fixture(self, course_fixture):
        """
        Populates test course with chapter, sequential, and 1 problems.
        The problem is visible only to Group "alpha".
        """
        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
                    XBlockFixtureDesc('vertical', 'Test Unit')
                )
            )
        )

    def create_and_verify_content_group(self, name, existing_groups):
        """
        Creates a new content group and verifies that it was properly created.
        """
        self.assertEqual(existing_groups, len(self.group_configurations_page.content_groups))
        if existing_groups == 0:
            self.group_configurations_page.create_first_content_group()
        else:
            self.group_configurations_page.add_content_group()
        config = self.group_configurations_page.content_groups[existing_groups]
        config.name = name
        # Save the content group
        self.assertEqual(config.get_text('.action-primary'), "Create")
        self.assertFalse(config.delete_button_is_present)
        config.save()
        self.assertIn(name, config.name)
        return config

    def test_no_content_groups_by_default(self):
        """
        Scenario: Ensure that message telling me to create a new content group is
            shown when no content groups exist.
        Given I have a course without content groups
        When I go to the Group Configuration page in Studio
        Then I see "You have not created any content groups yet." message
        """
        self.group_configurations_page.visit()
        self.assertTrue(self.group_configurations_page.no_content_groups_message_is_present)
        self.assertIn(
            "You have not created any content groups yet.",
            self.group_configurations_page.no_content_groups_message_text
        )

    def test_can_create_and_edit_content_groups(self):
        """
        Scenario: Ensure that the content groups can be created and edited correctly.
        Given I have a course without content groups
        When I click button 'Add your first Content Group'
        And I set new the name and click the button 'Create'
        Then I see the new content is added and has correct data
        And I click 'New Content Group' button
        And I set the name and click the button 'Create'
        Then I see the second content group is added and has correct data
        When I edit the second content group
        And I change the name and click the button 'Save'
        Then I see the second content group is saved successfully and has the new name
        """
        self.group_configurations_page.visit()
        self.create_and_verify_content_group("New Content Group", 0)
        second_config = self.create_and_verify_content_group("Second Content Group", 1)

        # Edit the second content group
        second_config.edit()
        second_config.name = "Updated Second Content Group"
        self.assertEqual(second_config.get_text('.action-primary'), "Save")
        second_config.save()

        self.assertIn("Updated Second Content Group", second_config.name)

    def test_cannot_delete_used_content_group(self):
        """
        Scenario: Ensure that the user cannot delete used content group.
        Given I have a course with 1 Content Group
        And I go to the Group Configuration page
        When I try to delete the Content Group with name "New Content Group"
        Then I see the delete button is disabled.
        """
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        'Configuration alpha,',
                        'Content Group Partition',
                        [Group("0", 'alpha')],
                        scheme="cohort"
                    )
                ],
            },
        })
        problem_data = dedent("""
            <problem markdown="Simple Problem" max_attempts="" weight="">
              <p>Choose Yes.</p>
              <choiceresponse>
                <checkboxgroup>
                  <choice correct="true">Yes</choice>
                </checkboxgroup>
              </choiceresponse>
            </problem>
        """)
        vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('problem', "VISIBLE TO ALPHA", data=problem_data, metadata={"group_access": {0: [0]}}),
        )
        self.group_configurations_page.visit()
        config = self.group_configurations_page.content_groups[0]
        self.assertTrue(config.delete_button_is_disabled)

    def test_can_delete_unused_content_group(self):
        """
        Scenario: Ensure that the user can delete unused content group.
        Given I have a course with 1 Content Group
        And I go to the Group Configuration page
        When I delete the Content Group with name "New Content Group"
        Then I see that there is no Content Group
        When I refresh the page
        Then I see that the content group has been deleted
        """
        self.group_configurations_page.visit()
        config = self.create_and_verify_content_group("New Content Group", 0)
        self.assertTrue(config.delete_button_is_present)

        self.assertEqual(len(self.group_configurations_page.content_groups), 1)

        # Delete content group
        config.delete()
        self.assertEqual(len(self.group_configurations_page.content_groups), 0)

        self.group_configurations_page.visit()
        self.assertEqual(len(self.group_configurations_page.content_groups), 0)

    def test_must_supply_name(self):
        """
        Scenario: Ensure that validation of the content group works correctly.
        Given I have a course without content groups
        And I create new content group without specifying a name click the button 'Create'
        Then I see error message "Content Group name is required."
        When I set a name and click the button 'Create'
        Then I see the content group is saved successfully
        """
        self.group_configurations_page.visit()
        self.group_configurations_page.create_first_content_group()
        config = self.group_configurations_page.content_groups[0]
        config.save()
        self.assertEqual(config.mode, 'edit')
        self.assertEqual("Group name is required", config.validation_message)
        config.name = "Content Group Name"
        config.save()
        self.assertIn("Content Group Name", config.name)

    def test_can_cancel_creation_of_content_group(self):
        """
        Scenario: Ensure that creation of a content group can be canceled correctly.
        Given I have a course without content groups
        When I click button 'Add your first Content Group'
        And I set new the name and click the button 'Cancel'
        Then I see that there is no content groups in the course
        """
        self.group_configurations_page.visit()
        self.group_configurations_page.create_first_content_group()
        config = self.group_configurations_page.content_groups[0]
        config.name = "Content Group"
        config.cancel()
        self.assertEqual(0, len(self.group_configurations_page.content_groups))

    def test_content_group_empty_usage(self):
        """
        Scenario: When content group is not used, ensure that the link to outline page works correctly.
        Given I have a course without content group
        And I create new content group
        Then I see a link to the outline page
        When I click on the outline link
        Then I see the outline page
        """
        self.group_configurations_page.visit()
        config = self.create_and_verify_content_group("New Content Group", 0)
        config.toggle()
        config.click_outline_anchor()

        # Waiting for the page load and verify that we've landed on course outline page
        self.outline_page.wait_for_page()
class GroupConfigurationsTest(ContainerBase, SplitTestMixin):
    """
    Tests that Group Configurations page works correctly with previously
    added configurations in Studio
    """
    __test__ = True

    def setUp(self):
        super(GroupConfigurationsTest, self).setUp()
        self.page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

    def _assert_fields(self, config, cid=None, name='', description='', groups=None):
        self.assertEqual(config.mode, 'details')

        if name:
            self.assertIn(name, config.name)

        if cid:
            self.assertEqual(cid, config.id)
        else:
            # To make sure that id is present on the page and it is not an empty.
            # We do not check the value of the id, because it's generated randomly and we cannot
            # predict this value
            self.assertTrue(config.id)

        # Expand the configuration
        config.toggle()

        if description:
            self.assertIn(description, config.description)

        if groups:
            allocation = int(math.floor(100 / len(groups)))
            self.assertEqual(groups, [group.name for group in config.groups])
            for group in config.groups:
                self.assertEqual(str(allocation) + "%", group.allocation)

        # Collapse the configuration
        config.toggle()

    def _add_split_test_to_vertical(self, number, group_configuration_metadata=None):
        """
        Add split test to vertical #`number`.

        If `group_configuration_metadata` is not None, use it to assign group configuration to split test.
        """
        vertical = self.course_fixture.get_nested_xblocks(category="vertical")[number]
        if group_configuration_metadata:
            split_test = XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata=group_configuration_metadata)
        else:
            split_test = XBlockFixtureDesc('split_test', 'Test Content Experiment')
        self.course_fixture.create_xblock(vertical.locator, split_test)
        return split_test

    def populate_course_fixture(self, course_fixture):
        course_fixture.add_advanced_settings({
            u"advanced_modules": {"value": ["split_test"]},
        })
        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
                    XBlockFixtureDesc('vertical', 'Test Unit')
                )
            )
        )

    def create_group_configuration_experiment(self, groups, associate_experiment):
        """
        Creates a Group Configuration containing a list of groups.
        Optionally creates a Content Experiment and associates it with previous Group Configuration.

        Returns group configuration or (group configuration, experiment xblock)
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(0, "Name", "Description.", groups),
                ],
            },
        })

        if associate_experiment:
            # Assign newly created group configuration to experiment
            vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0]
            split_test = XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata={'user_partition_id': 0})
            self.course_fixture.create_xblock(vertical.locator, split_test)

        # Go to the Group Configuration Page
        self.page.visit()
        config = self.page.experiment_group_configurations[0]

        if associate_experiment:
            return config, split_test
        return config

    def publish_unit_in_lms_and_view(self, courseware_page, publish=True):
        """
        Given course outline page, publish first unit and view it in LMS when publish is false, it will only view
        """
        self.outline_page.visit()
        self.outline_page.expand_all_subsections()
        section = self.outline_page.section_at(0)
        unit = section.subsection_at(0).unit_at(0).go_to()

        # I publish and view in LMS and it is rendered correctly
        if publish:
            unit.publish_action.click()
        unit.view_published_version()
        self.assertEqual(len(self.browser.window_handles), 2)
        courseware_page.wait_for_page()

    def get_select_options(self, page, selector):
        """
        Get list of options of dropdown that is specified by selector on a given page.
        """
        select_element = page.q(css=selector)
        self.assertTrue(select_element.is_present())
        return [option.text for option in Select(select_element[0]).options]

    def test_no_group_configurations_added(self):
        """
        Scenario: Ensure that message telling me to create a new group configuration is
        shown when group configurations were not added.
        Given I have a course without group configurations
        When I go to the Group Configuration page in Studio
        Then I see "You have not created any group configurations yet." message
        """
        self.page.visit()
        self.assertTrue(self.page.experiment_group_sections_present)
        self.assertTrue(self.page.no_experiment_groups_message_is_present)
        self.assertIn(
            "You have not created any group configurations yet.",
            self.page.no_experiment_groups_message_text
        )

    def test_group_configurations_have_correct_data(self):
        """
        Scenario: Ensure that the group configuration is rendered correctly in expanded/collapsed mode.
        Given I have a course with 2 group configurations
        And I go to the Group Configuration page in Studio
        And I work with the first group configuration
        And I see `name`, `id` are visible and have correct values
        When I expand the first group configuration
        Then I see `description` and `groups` appear and also have correct values
        And I do the same checks for the second group configuration
        """
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        'Name of the Group Configuration',
                        'Description of the group configuration.',
                        [Group("0", 'Group 0'), Group("1", 'Group 1')]
                    ),
                    create_user_partition_json(
                        1,
                        'Name of second Group Configuration',
                        'Second group configuration.',
                        [Group("0", 'Alpha'), Group("1", 'Beta'), Group("2", 'Gamma')]
                    ),
                ],
            },
        })

        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        # no groups when the the configuration is collapsed
        self.assertEqual(len(config.groups), 0)
        self._assert_fields(
            config,
            cid="0", name="Name of the Group Configuration",
            description="Description of the group configuration.",
            groups=["Group 0", "Group 1"]
        )

        config = self.page.experiment_group_configurations[1]

        self._assert_fields(
            config,
            name="Name of second Group Configuration",
            description="Second group configuration.",
            groups=["Alpha", "Beta", "Gamma"]
        )

    def test_can_create_and_edit_group_configuration(self):
        """
        Scenario: Ensure that the group configuration can be created and edited correctly.
        Given I have a course without group configurations
        When I click button 'Create new Group Configuration'
        And I set new name and description, change name for the 2nd default group, add one new group
        And I click button 'Create'
        Then I see the new group configuration is added and has correct data
        When I edit the group group_configuration
        And I change the name and description, add new group, remove old one and change name for the Group A
        And I click button 'Save'
        Then I see the group configuration is saved successfully and has the new data
        """
        self.page.visit()
        self.assertEqual(len(self.page.experiment_group_configurations), 0)
        # Create new group configuration
        self.page.create_experiment_group_configuration()
        config = self.page.experiment_group_configurations[0]
        config.name = "New Group Configuration Name"
        config.description = "New Description of the group configuration."
        config.groups[1].name = "New Group Name"
        # Add new group
        config.add_group()  # Group C

        # Save the configuration
        self.assertEqual(config.get_text('.action-primary'), "Create")
        self.assertFalse(config.delete_button_is_present)
        config.save()

        self._assert_fields(
            config,
            name="New Group Configuration Name",
            description="New Description of the group configuration.",
            groups=["Group A", "New Group Name", "Group C"]
        )

        # Edit the group configuration
        config.edit()
        # Update fields
        self.assertTrue(config.id)
        config.name = "Second Group Configuration Name"
        config.description = "Second Description of the group configuration."
        self.assertEqual(config.get_text('.action-primary'), "Save")
        # Add new group
        config.add_group()  # Group D
        # Remove group with name "New Group Name"
        config.groups[1].remove()
        # Rename Group A
        config.groups[0].name = "First Group"
        # Save the configuration
        config.save()

        self._assert_fields(
            config,
            name="Second Group Configuration Name",
            description="Second Description of the group configuration.",
            groups=["First Group", "Group C", "Group D"]
        )

    def test_focus_management_in_experiment_group_inputs(self):
        """
        Scenario: Ensure that selecting the focus inputs in the groups list
        sets the .is-focused class on the fieldset
        Given I have a course with experiment group configurations
        When I click the name of the first group
        Then the fieldset wrapping the group names whould get class .is-focused
        When I click away from the first group
        Then the fieldset should not have class .is-focused anymore
        """
        self.page.visit()
        self.page.create_experiment_group_configuration()
        config = self.page.experiment_group_configurations[0]
        group_a = config.groups[0]

        # Assert the fieldset doesn't have .is-focused class
        self.assertFalse(self.page.q(css="fieldset.groups-fields.is-focused").visible)

        # Click on the Group A input field
        self.page.q(css=group_a.prefix).click()

        # Assert the fieldset has .is-focused class applied
        self.assertTrue(self.page.q(css="fieldset.groups-fields.is-focused").visible)

        # Click away
        self.page.q(css=".page-header").click()

        # Assert the fieldset doesn't have .is-focused class
        self.assertFalse(self.page.q(css="fieldset.groups-fields.is-focused").visible)

    def test_use_group_configuration(self):
        """
        Scenario: Ensure that the group configuration can be used by split_module correctly
        Given I have a course without group configurations
        When I create new group configuration
        And I set new name and add a new group, save the group configuration
        And I go to the unit page in Studio
        And I add new advanced module "Content Experiment"
        When I assign created group configuration to the module
        Then I see the module has correct groups
        """
        self.page.visit()
        # Create new group configuration
        self.page.create_experiment_group_configuration()
        config = self.page.experiment_group_configurations[0]
        config.name = "New Group Configuration Name"
        # Add new group
        config.add_group()
        config.groups[2].name = "New group"
        # Save the configuration
        config.save()

        split_test = self._add_split_test_to_vertical(number=0)

        container = ContainerPage(self.browser, split_test.locator)
        container.visit()
        container.edit()
        component_editor = ComponentEditorView(self.browser, container.locator)
        component_editor.set_select_value_and_save('Group Configuration', 'New Group Configuration Name')
        self.verify_groups(container, ['Group A', 'Group B', 'New group'], [])

    def test_container_page_active_verticals_names_are_synced(self):
        """
        Scenario: Ensure that the Content Experiment display synced vertical names and correct groups.
        Given I have a course with group configuration
        And I go to the Group Configuration page in Studio
        And I edit the name of the group configuration, add new group and remove old one
        And I change the name for the group "New group" to "Second Group"
        And I go to the Container page in Studio
        And I edit the Content Experiment
        Then I see the group configuration name is changed in `Group Configuration` dropdown
        And the group configuration name is changed on container page
        And I see the module has 2 active groups and one inactive
        And I see "Add missing groups" link exists
        When I click on "Add missing groups" link
        The I see the module has 3 active groups and one inactive
        """
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        'Name of the Group Configuration',
                        'Description of the group configuration.',
                        [Group("0", 'Group A'), Group("1", 'Group B'), Group("2", 'Group C')]
                    ),
                ],
            },
        })

        # Add split test to vertical and assign newly created group configuration to it
        split_test = self._add_split_test_to_vertical(number=0, group_configuration_metadata={'user_partition_id': 0})

        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.edit()
        config.name = "Second Group Configuration Name"
        # `Group C` -> `Second Group`
        config.groups[2].name = "Second Group"
        # Add new group
        config.add_group()  # Group D
        # Remove Group A
        config.groups[0].remove()
        # Save the configuration
        config.save()

        container = ContainerPage(self.browser, split_test.locator)
        container.visit()
        container.edit()
        component_editor = ComponentEditorView(self.browser, container.locator)
        self.assertEqual(
            "Second Group Configuration Name",
            component_editor.get_selected_option_text('Group Configuration')
        )
        component_editor.cancel()
        self.assertIn(
            "Second Group Configuration Name",
            container.get_xblock_information_message()
        )
        self.verify_groups(
            container, ['Group B', 'Second Group'], ['Group ID 0'],
            verify_missing_groups_not_present=False
        )
        # Click the add button and verify that the groups were added on the page
        container.add_missing_groups()
        self.verify_groups(container, ['Group B', 'Second Group', 'Group D'], ['Group ID 0'])

    def test_can_cancel_creation_of_group_configuration(self):
        """
        Scenario: Ensure that creation of the group configuration can be canceled correctly.
        Given I have a course without group configurations
        When I click button 'Create new Group Configuration'
        And I set new name and description, add 1 additional group
        And I click button 'Cancel'
        Then I see that there is no new group configurations in the course
        """
        self.page.visit()

        self.assertEqual(len(self.page.experiment_group_configurations), 0)
        # Create new group configuration
        self.page.create_experiment_group_configuration()

        config = self.page.experiment_group_configurations[0]
        config.name = "Name of the Group Configuration"
        config.description = "Description of the group configuration."
        # Add new group
        config.add_group()  # Group C
        # Cancel the configuration
        config.cancel()

        self.assertEqual(len(self.page.experiment_group_configurations), 0)

    def test_can_cancel_editing_of_group_configuration(self):
        """
        Scenario: Ensure that editing of the group configuration can be canceled correctly.
        Given I have a course with group configuration
        When I go to the edit mode of the group configuration
        And I set new name and description, add 2 additional groups
        And I click button 'Cancel'
        Then I see that new changes were discarded
        """
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        'Name of the Group Configuration',
                        'Description of the group configuration.',
                        [Group("0", 'Group 0'), Group("1", 'Group 1')]
                    ),
                    create_user_partition_json(
                        1,
                        'Name of second Group Configuration',
                        'Second group configuration.',
                        [Group("0", 'Alpha'), Group("1", 'Beta'), Group("2", 'Gamma')]
                    ),
                ],
            },
        })
        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.name = "New Group Configuration Name"
        config.description = "New Description of the group configuration."
        # Add 2 new groups
        config.add_group()  # Group C
        config.add_group()  # Group D
        # Cancel the configuration
        config.cancel()

        self._assert_fields(
            config,
            name="Name of the Group Configuration",
            description="Description of the group configuration.",
            groups=["Group 0", "Group 1"]
        )

    def test_group_configuration_validation(self):
        """
        Scenario: Ensure that validation of the group configuration works correctly.
        Given I have a course without group configurations
        And I create new group configuration with 2 default groups
        When I set only description and try to save
        Then I see error message "Group Configuration name is required."
        When I set a name
        And I delete the name of one of the groups and try to save
        Then I see error message "All groups must have a name"
        When I delete all the groups and try to save
        Then I see error message "There must be at least one group."
        When I add a group and try to save
        Then I see the group configuration is saved successfully
        """
        def try_to_save_and_verify_error_message(message):
            # Try to save
            config.save()
            # Verify that configuration is still in editing mode
            self.assertEqual(config.mode, 'edit')
            # Verify error message
            self.assertEqual(message, config.validation_message)

        self.page.visit()
        # Create new group configuration
        self.page.create_experiment_group_configuration()
        # Leave empty required field
        config = self.page.experiment_group_configurations[0]
        config.description = "Description of the group configuration."

        try_to_save_and_verify_error_message("Group Configuration name is required.")

        # Set required field
        config.name = "Name of the Group Configuration"
        config.groups[1].name = ''
        try_to_save_and_verify_error_message("All groups must have a name.")
        config.groups[0].remove()
        config.groups[0].remove()
        try_to_save_and_verify_error_message("There must be at least one group.")
        config.add_group()

        # Save the configuration
        config.save()

        self._assert_fields(
            config,
            name="Name of the Group Configuration",
            description="Description of the group configuration.",
            groups=["Group A"]
        )

    def test_group_configuration_empty_usage(self):
        """
        Scenario: When group configuration is not used, ensure that the link to outline page works correctly.
        Given I have a course without group configurations
        And I create new group configuration with 2 default groups
        Then I see a link to the outline page
        When I click on the outline link
        Then I see the outline page
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        "Name",
                        "Description.",
                        [Group("0", "Group A"), Group("1", "Group B")]
                    ),
                ],
            },
        })

        # Go to the Group Configuration Page and click on outline anchor
        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.toggle()
        config.click_outline_anchor()

        # Waiting for the page load and verify that we've landed on course outline page
        self.outline_page.wait_for_page()

    def test_group_configuration_non_empty_usage(self):
        """
        Scenario: When group configuration is used, ensure that the links to units using a group configuration work correctly.
        Given I have a course without group configurations
        And I create new group configuration with 2 default groups
        And I create a unit and assign the newly created group configuration
        And open the Group Configuration page
        Then I see a link to the newly created unit
        When I click on the unit link
        Then I see correct unit page
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        "Name",
                        "Description.",
                        [Group("0", "Group A"), Group("1", "Group B")]
                    ),
                ],
            },
        })

        # Assign newly created group configuration to unit
        vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata={'user_partition_id': 0})
        )
        unit = CourseOutlineUnit(self.browser, vertical.locator)

        # Go to the Group Configuration Page and click unit anchor
        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.toggle()
        usage = config.usages[0]
        config.click_unit_anchor()

        unit = ContainerPage(self.browser, vertical.locator)
        # Waiting for the page load and verify that we've landed on the unit page
        unit.wait_for_page()

        self.assertIn(unit.name, usage)

    def test_can_delete_unused_group_configuration(self):
        """
        Scenario: Ensure that the user can delete unused group configuration.
        Given I have a course with 2 group configurations
        And I go to the Group Configuration page
        When I delete the Group Configuration with name "Configuration 1"
        Then I see that there is one Group Configuration
        When I edit the Group Configuration with name "Configuration 2"
        And I delete the Group Configuration with name "Configuration 2"
        Then I see that the are no Group Configurations
        """
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        'Configuration 1',
                        'Description of the group configuration.',
                        [Group("0", 'Group 0'), Group("1", 'Group 1')]
                    ),
                    create_user_partition_json(
                        1,
                        'Configuration 2',
                        'Second group configuration.',
                        [Group("0", 'Alpha'), Group("1", 'Beta'), Group("2", 'Gamma')]
                    )
                ],
            },
        })
        self.page.visit()

        self.assertEqual(len(self.page.experiment_group_configurations), 2)
        config = self.page.experiment_group_configurations[1]
        # Delete first group configuration via detail view
        config.delete()
        self.assertEqual(len(self.page.experiment_group_configurations), 1)

        config = self.page.experiment_group_configurations[0]
        config.edit()
        self.assertFalse(config.delete_button_is_disabled)
        # Delete first group configuration via edit view
        config.delete()
        self.assertEqual(len(self.page.experiment_group_configurations), 0)

    def test_cannot_delete_used_group_configuration(self):
        """
        Scenario: Ensure that the user cannot delete unused group configuration.
        Given I have a course with group configuration that is used in the Content Experiment
        When I go to the Group Configuration page
        Then I do not see delete button and I see a note about that
        When I edit the Group Configuration
        Then I do not see delete button and I see the note about that
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        "Name",
                        "Description.",
                        [Group("0", "Group A"), Group("1", "Group B")]
                    )
                ],
            },
        })
        vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata={'user_partition_id': 0})
        )
        # Go to the Group Configuration Page and click unit anchor
        self.page.visit()

        config = self.page.experiment_group_configurations[0]
        self.assertTrue(config.delete_button_is_disabled)
        self.assertIn('Cannot delete when in use by an experiment', config.delete_note)

        config.edit()
        self.assertTrue(config.delete_button_is_disabled)
        self.assertIn('Cannot delete when in use by an experiment', config.delete_note)

    def test_easy_access_from_experiment(self):
        """
        Scenario: When a Content Experiment uses a Group Configuration,
        ensure that the link to that Group Configuration works correctly.

        Given I have a course with two Group Configurations
        And Content Experiment is assigned to one Group Configuration
        Then I see a link to Group Configuration
        When I click on the Group Configuration link
        Then I see the Group Configurations page
        And I see that appropriate Group Configuration is expanded.
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        "Name",
                        "Description.",
                        [Group("0", "Group A"), Group("1", "Group B")]
                    ),
                    create_user_partition_json(
                        1,
                        'Name of second Group Configuration',
                        'Second group configuration.',
                        [Group("0", 'Alpha'), Group("1", 'Beta'), Group("2", 'Gamma')]
                    ),
                ],
            },
        })

        # Assign newly created group configuration to unit
        vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata={'user_partition_id': 1})
        )

        unit = ContainerPage(self.browser, vertical.locator)
        unit.visit()
        experiment = unit.xblocks[0]

        group_configuration_link_name = experiment.group_configuration_link_name

        experiment.go_to_group_configuration_page()
        self.page.wait_for_page()

        # Appropriate Group Configuration is expanded.
        self.assertFalse(self.page.experiment_group_configurations[0].is_expanded)
        self.assertTrue(self.page.experiment_group_configurations[1].is_expanded)

        self.assertEqual(
            group_configuration_link_name,
            self.page.experiment_group_configurations[1].name
        )

    def test_details_error_validation_message(self):
        """
        Scenario: When a Content Experiment uses a Group Configuration, ensure
        that an error validation message appears if necessary.

        Given I have a course with a Group Configuration containing two Groups
        And a Content Experiment is assigned to that Group Configuration
        When I go to the Group Configuration Page
        Then I do not see a error icon and message in the Group Configuration details view.
        When I add a Group
        Then I see an error icon and message in the Group Configuration details view
        """

        # Create group configuration and associated experiment
        config, _ = self.create_group_configuration_experiment([Group("0", "Group A"), Group("1", "Group B")], True)

        # Display details view
        config.toggle()
        # Check that error icon and message are not present
        self.assertFalse(config.details_error_icon_is_present)
        self.assertFalse(config.details_message_is_present)

        # Add a group
        config.toggle()
        config.edit()
        config.add_group()
        config.save()

        # Display details view
        config.toggle()
        # Check that error icon and message are present
        self.assertTrue(config.details_error_icon_is_present)
        self.assertTrue(config.details_message_is_present)
        self.assertIn(
            "This content experiment has issues that affect content visibility.",
            config.details_message_text
        )

    def test_details_warning_validation_message(self):
        """
        Scenario: When a Content Experiment uses a Group Configuration, ensure
        that a warning validation message appears if necessary.

        Given I have a course with a Group Configuration containing three Groups
        And a Content Experiment is assigned to that Group Configuration
        When I go to the Group Configuration Page
        Then I do not see a warning icon and message in the Group Configuration details view.
        When I remove a Group
        Then I see a warning icon and message in the Group Configuration details view
        """

        # Create group configuration and associated experiment
        config, _ = self.create_group_configuration_experiment([Group("0", "Group A"), Group("1", "Group B"), Group("2", "Group C")], True)

        # Display details view
        config.toggle()
        # Check that warning icon and message are not present
        self.assertFalse(config.details_warning_icon_is_present)
        self.assertFalse(config.details_message_is_present)

        # Remove a group
        config.toggle()
        config.edit()
        config.groups[2].remove()
        config.save()

        # Display details view
        config.toggle()
        # Check that warning icon and message are present
        self.assertTrue(config.details_warning_icon_is_present)
        self.assertTrue(config.details_message_is_present)
        self.assertIn(
            "This content experiment has issues that affect content visibility.",
            config.details_message_text
        )

    def test_edit_warning_message_empty_usage(self):
        """
        Scenario: When a Group Configuration is not used, ensure that there are no warning icon and message.

        Given I have a course with a Group Configuration containing two Groups
        When I edit the Group Configuration
        Then I do not see a warning icon and message
        """

        # Create a group configuration with no associated experiment and display edit view
        config = self.create_group_configuration_experiment([Group("0", "Group A"), Group("1", "Group B")], False)
        config.edit()
        # Check that warning icon and message are not present
        self.assertFalse(config.edit_warning_icon_is_present)
        self.assertFalse(config.edit_warning_message_is_present)

    def test_edit_warning_message_non_empty_usage(self):
        """
        Scenario: When a Group Configuration is used, ensure that there are a warning icon and message.

        Given I have a course with a Group Configuration containing two Groups
        When I edit the Group Configuration
        Then I see a warning icon and message
        """

        # Create a group configuration with an associated experiment and display edit view
        config, _ = self.create_group_configuration_experiment([Group("0", "Group A"), Group("1", "Group B")], True)
        config.edit()
        # Check that warning icon and message are present
        self.assertTrue(config.edit_warning_icon_is_present)
        self.assertTrue(config.edit_warning_message_is_present)
        self.assertIn(
            "This configuration is currently used in content experiments. If you make changes to the groups, you may need to edit those experiments.",
            config.edit_warning_message_text
        )

    def publish_unit_and_verify_groups_in_lms(self, courseware_page, group_names, publish=True):
        """
        Publish first unit in LMS and verify that Courseware page has given Groups
        """
        self.publish_unit_in_lms_and_view(courseware_page, publish)
        self.assertEqual(u'split_test', courseware_page.xblock_component_type())
        self.assertTrue(courseware_page.q(css=".split-test-select").is_present())
        rendered_group_names = self.get_select_options(page=courseware_page, selector=".split-test-select")
        self.assertListEqual(group_names, rendered_group_names)

    def test_split_test_LMS_staff_view(self):
        """
        Scenario: Ensure that split test is correctly rendered in LMS staff mode as it is
                  and after inactive group removal.

        Given I have a course with group configurations and split test that assigned to first group configuration
        Then I publish split test and view it in LMS in staff view
        And it is rendered correctly
        Then I go to group configuration and delete group
        Then I publish split test and view it in LMS in staff view
        And it is rendered correctly
        Then I go to split test and delete inactive vertical
        Then I publish unit and view unit in LMS in staff view
        And it is rendered correctly
        """

        config, split_test = self.create_group_configuration_experiment([Group("0", "Group A"), Group("1", "Group B"), Group("2", "Group C")], True)
        container = ContainerPage(self.browser, split_test.locator)

        # render in LMS correctly
        courseware_page = CoursewarePage(self.browser, self.course_id)
        self.publish_unit_and_verify_groups_in_lms(courseware_page, [u'Group A', u'Group B', u'Group C'])

        # I go to group configuration and delete group
        self.page.visit()
        self.page.q(css='.group-toggle').first.click()
        config.edit()
        config.groups[2].remove()
        config.save()
        self.page.q(css='.group-toggle').first.click()
        self._assert_fields(config, name="Name", description="Description", groups=["Group A", "Group B"])
        self.browser.close()
        self.browser.switch_to_window(self.browser.window_handles[0])

        # render in LMS to see how inactive vertical is rendered
        self.publish_unit_and_verify_groups_in_lms(
            courseware_page,
            [u'Group A', u'Group B', u'Group ID 2 (inactive)'],
            publish=False
        )

        self.browser.close()
        self.browser.switch_to_window(self.browser.window_handles[0])

        # I go to split test and delete inactive vertical
        container.visit()
        container.delete(0)

        # render in LMS again
        self.publish_unit_and_verify_groups_in_lms(courseware_page, [u'Group A', u'Group B'])
Beispiel #28
0
class GroupConfigurationsTest(ContainerBase, SplitTestMixin):
    """
    Tests that Group Configurations page works correctly with previously
    added configurations in Studio
    """
    __test__ = True
    shard = 15

    def setUp(self):
        super(GroupConfigurationsTest, self).setUp()
        self.page = GroupConfigurationsPage(self.browser,
                                            self.course_info['org'],
                                            self.course_info['number'],
                                            self.course_info['run'])

        self.outline_page = CourseOutlinePage(self.browser,
                                              self.course_info['org'],
                                              self.course_info['number'],
                                              self.course_info['run'])

    def _assert_fields(self,
                       config,
                       cid=None,
                       name='',
                       description='',
                       groups=None):
        self.assertEqual(config.mode, 'details')

        if name:
            self.assertIn(name, config.name)

        if cid:
            self.assertEqual(cid, config.id)
        else:
            # To make sure that id is present on the page and it is not an empty.
            # We do not check the value of the id, because it's generated randomly and we cannot
            # predict this value
            self.assertTrue(config.id)

        # Expand the configuration
        config.toggle()

        if description:
            self.assertIn(description, config.description)

        if groups:
            allocation = int(math.floor(100 / len(groups)))
            self.assertEqual(groups, [group.name for group in config.groups])
            for group in config.groups:
                self.assertEqual(str(allocation) + "%", group.allocation)

        # Collapse the configuration
        config.toggle()

    def _add_split_test_to_vertical(self,
                                    number,
                                    group_configuration_metadata=None):
        """
        Add split test to vertical #`number`.

        If `group_configuration_metadata` is not None, use it to assign group configuration to split test.
        """
        vertical = self.course_fixture.get_nested_xblocks(
            category="vertical")[number]
        if group_configuration_metadata:
            split_test = XBlockFixtureDesc(
                'split_test',
                'Test Content Experiment',
                metadata=group_configuration_metadata)
        else:
            split_test = XBlockFixtureDesc('split_test',
                                           'Test Content Experiment')
        self.course_fixture.create_xblock(vertical.locator, split_test)
        return split_test

    def populate_course_fixture(self, course_fixture):
        course_fixture.add_advanced_settings({
            u"advanced_modules": {
                "value": ["split_test"]
            },
        })
        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section').add_children(
                XBlockFixtureDesc('sequential',
                                  'Test Subsection').add_children(
                                      XBlockFixtureDesc(
                                          'vertical', 'Test Unit'))))

    def create_group_configuration_experiment(self, groups,
                                              associate_experiment):
        """
        Creates a Group Configuration containing a list of groups.
        Optionally creates a Content Experiment and associates it with previous Group Configuration.

        Returns group configuration or (group configuration, experiment xblock)
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(0, "Name", "Description.",
                                                   groups),
                    ],
                },
            })

        if associate_experiment:
            # Assign newly created group configuration to experiment
            vertical = self.course_fixture.get_nested_xblocks(
                category="vertical")[0]
            split_test = XBlockFixtureDesc('split_test',
                                           'Test Content Experiment',
                                           metadata={'user_partition_id': 0})
            self.course_fixture.create_xblock(vertical.locator, split_test)

        # Go to the Group Configuration Page
        self.page.visit()
        config = self.page.experiment_group_configurations[0]

        if associate_experiment:
            return config, split_test
        return config

    def publish_unit_in_lms_and_view(self, courseware_page, publish=True):
        """
        Given course outline page, publish first unit and view it in LMS when publish is false, it will only view
        """
        self.outline_page.visit()
        self.outline_page.expand_all_subsections()
        section = self.outline_page.section_at(0)
        unit = section.subsection_at(0).unit_at(0).go_to()

        # I publish and view in LMS and it is rendered correctly
        if publish:
            unit.publish()
        unit.view_published_version()
        self.assertEqual(len(self.browser.window_handles), 2)
        courseware_page.wait_for_page()

    def get_select_options(self, page, selector):
        """
        Get list of options of dropdown that is specified by selector on a given page.
        """
        select_element = page.q(css=selector)
        self.assertTrue(select_element.is_present())
        return [option.text for option in Select(select_element[0]).options]

    def test_no_group_configurations_added(self):
        """
        Scenario: Ensure that message telling me to create a new group configuration is
        shown when group configurations were not added.
        Given I have a course without group configurations
        When I go to the Group Configuration page in Studio
        Then I see "You have not created any group configurations yet." message
        """
        self.page.visit()
        self.assertTrue(self.page.experiment_group_sections_present)
        self.assertTrue(self.page.no_experiment_groups_message_is_present)
        self.assertIn("You have not created any group configurations yet.",
                      self.page.no_experiment_groups_message_text)

    def test_group_configurations_have_correct_data(self):
        """
        Scenario: Ensure that the group configuration is rendered correctly in expanded/collapsed mode.
        Given I have a course with 2 group configurations
        And I go to the Group Configuration page in Studio
        And I work with the first group configuration
        And I see `name`, `id` are visible and have correct values
        When I expand the first group configuration
        Then I see `description` and `groups` appear and also have correct values
        And I do the same checks for the second group configuration
        """
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, 'Name of the Group Configuration',
                            'Description of the group configuration.',
                            [Group("0", 'Group 0'),
                             Group("1", 'Group 1')]),
                        create_user_partition_json(
                            1, 'Name of second Group Configuration',
                            'Second group configuration.', [
                                Group("0", 'Alpha'),
                                Group("1", 'Beta'),
                                Group("2", 'Gamma')
                            ]),
                    ],
                },
            })

        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        # no groups when the the configuration is collapsed
        self.assertEqual(len(config.groups), 0)
        self._assert_fields(
            config,
            cid="0",
            name="Name of the Group Configuration",
            description="Description of the group configuration.",
            groups=["Group 0", "Group 1"])

        config = self.page.experiment_group_configurations[1]

        self._assert_fields(config,
                            name="Name of second Group Configuration",
                            description="Second group configuration.",
                            groups=["Alpha", "Beta", "Gamma"])

    def test_can_create_and_edit_group_configuration(self):
        """
        Scenario: Ensure that the group configuration can be created and edited correctly.
        Given I have a course without group configurations
        When I click button 'Create new Group Configuration'
        And I set new name and description, change name for the 2nd default group, add one new group
        And I click button 'Create'
        Then I see the new group configuration is added and has correct data
        When I edit the group group_configuration
        And I change the name and description, add new group, remove old one and change name for the Group A
        And I click button 'Save'
        Then I see the group configuration is saved successfully and has the new data
        """
        self.page.visit()
        self.assertEqual(len(self.page.experiment_group_configurations), 0)
        # Create new group configuration
        self.page.create_experiment_group_configuration()
        config = self.page.experiment_group_configurations[0]
        config.name = "New Group Configuration Name"
        config.description = "New Description of the group configuration."
        config.groups[1].name = "New Group Name"
        # Add new group
        config.add_group()  # Group C

        # Save the configuration
        self.assertEqual(config.get_text('.action-primary'), "Create")
        self.assertFalse(config.delete_button_is_present)
        config.save()

        self._assert_fields(
            config,
            name="New Group Configuration Name",
            description="New Description of the group configuration.",
            groups=["Group A", "New Group Name", "Group C"])

        # Edit the group configuration
        config.edit()
        # Update fields
        self.assertTrue(config.id)
        config.name = "Second Group Configuration Name"
        config.description = "Second Description of the group configuration."
        self.assertEqual(config.get_text('.action-primary'), "Save")
        # Add new group
        config.add_group()  # Group D
        # Remove group with name "New Group Name"
        config.groups[1].remove()
        # Rename Group A
        config.groups[0].name = "First Group"
        # Save the configuration
        config.save()

        self._assert_fields(
            config,
            name="Second Group Configuration Name",
            description="Second Description of the group configuration.",
            groups=["First Group", "Group C", "Group D"])

    def test_focus_management_in_experiment_group_inputs(self):
        """
        Scenario: Ensure that selecting the focus inputs in the groups list
        sets the .is-focused class on the fieldset
        Given I have a course with experiment group configurations
        When I click the name of the first group
        Then the fieldset wrapping the group names whould get class .is-focused
        When I click away from the first group
        Then the fieldset should not have class .is-focused anymore
        """
        self.page.visit()
        self.page.create_experiment_group_configuration()
        config = self.page.experiment_group_configurations[0]
        group_a = config.groups[0]

        # Assert the fieldset doesn't have .is-focused class
        self.assertFalse(
            self.page.q(css="fieldset.groups-fields.is-focused").visible)

        # Click on the Group A input field
        self.page.q(css=group_a.prefix).click()

        # Assert the fieldset has .is-focused class applied
        self.assertTrue(
            self.page.q(css="fieldset.groups-fields.is-focused").visible)

        # Click away
        self.page.q(css=".page-header").click()

        # Assert the fieldset doesn't have .is-focused class
        self.assertFalse(
            self.page.q(css="fieldset.groups-fields.is-focused").visible)

    def test_use_group_configuration(self):
        """
        Scenario: Ensure that the group configuration can be used by split_module correctly
        Given I have a course without group configurations
        When I create new group configuration
        And I set new name and add a new group, save the group configuration
        And I go to the unit page in Studio
        And I add new advanced module "Content Experiment"
        When I assign created group configuration to the module
        Then I see the module has correct groups
        """
        self.page.visit()
        # Create new group configuration
        self.page.create_experiment_group_configuration()
        config = self.page.experiment_group_configurations[0]
        config.name = "New Group Configuration Name"
        # Add new group
        config.add_group()
        config.groups[2].name = "New group"
        # Save the configuration
        config.save()

        split_test = self._add_split_test_to_vertical(number=0)

        container = ContainerPage(self.browser, split_test.locator)
        container.visit()
        container.edit()
        component_editor = XBlockEditorView(self.browser, container.locator)
        component_editor.set_select_value_and_save(
            'Group Configuration', 'New Group Configuration Name')
        self.verify_groups(container, ['Group A', 'Group B', 'New group'], [])

    def test_container_page_active_verticals_names_are_synced(self):
        """
        Scenario: Ensure that the Content Experiment display synced vertical names and correct groups.
        Given I have a course with group configuration
        And I go to the Group Configuration page in Studio
        And I edit the name of the group configuration, add new group and remove old one
        And I change the name for the group "New group" to "Second Group"
        And I go to the Container page in Studio
        And I edit the Content Experiment
        Then I see the group configuration name is changed in `Group Configuration` dropdown
        And the group configuration name is changed on container page
        And I see the module has 2 active groups and one inactive
        And I see "Add missing groups" link exists
        When I click on "Add missing groups" link
        The I see the module has 3 active groups and one inactive
        """
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, 'Name of the Group Configuration',
                            'Description of the group configuration.', [
                                Group("0", 'Group A'),
                                Group("1", 'Group B'),
                                Group("2", 'Group C')
                            ]),
                    ],
                },
            })

        # Add split test to vertical and assign newly created group configuration to it
        split_test = self._add_split_test_to_vertical(
            number=0, group_configuration_metadata={'user_partition_id': 0})

        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.edit()
        config.name = "Second Group Configuration Name"
        # `Group C` -> `Second Group`
        config.groups[2].name = "Second Group"
        # Add new group
        config.add_group()  # Group D
        # Remove Group A
        config.groups[0].remove()
        # Save the configuration
        config.save()

        container = ContainerPage(self.browser, split_test.locator)
        container.visit()
        container.edit()
        component_editor = XBlockEditorView(self.browser, container.locator)
        self.assertEqual(
            "Second Group Configuration Name",
            component_editor.get_selected_option_text('Group Configuration'))
        component_editor.cancel()
        self.assertIn("Second Group Configuration Name",
                      container.get_xblock_information_message())
        self.verify_groups(container, ['Group B', 'Second Group'],
                           ['Group ID 0'],
                           verify_missing_groups_not_present=False)
        # Click the add button and verify that the groups were added on the page
        container.add_missing_groups()
        self.verify_groups(container, ['Group B', 'Second Group', 'Group D'],
                           ['Group ID 0'])

    def test_can_cancel_creation_of_group_configuration(self):
        """
        Scenario: Ensure that creation of the group configuration can be canceled correctly.
        Given I have a course without group configurations
        When I click button 'Create new Group Configuration'
        And I set new name and description, add 1 additional group
        And I click button 'Cancel'
        Then I see that there is no new group configurations in the course
        """
        self.page.visit()

        self.assertEqual(len(self.page.experiment_group_configurations), 0)
        # Create new group configuration
        self.page.create_experiment_group_configuration()

        config = self.page.experiment_group_configurations[0]
        config.name = "Name of the Group Configuration"
        config.description = "Description of the group configuration."
        # Add new group
        config.add_group()  # Group C
        # Cancel the configuration
        config.cancel()

        self.assertEqual(len(self.page.experiment_group_configurations), 0)

    def test_can_cancel_editing_of_group_configuration(self):
        """
        Scenario: Ensure that editing of the group configuration can be canceled correctly.
        Given I have a course with group configuration
        When I go to the edit mode of the group configuration
        And I set new name and description, add 2 additional groups
        And I click button 'Cancel'
        Then I see that new changes were discarded
        """
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, 'Name of the Group Configuration',
                            'Description of the group configuration.',
                            [Group("0", 'Group 0'),
                             Group("1", 'Group 1')]),
                        create_user_partition_json(
                            1, 'Name of second Group Configuration',
                            'Second group configuration.', [
                                Group("0", 'Alpha'),
                                Group("1", 'Beta'),
                                Group("2", 'Gamma')
                            ]),
                    ],
                },
            })
        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.name = "New Group Configuration Name"
        config.description = "New Description of the group configuration."
        # Add 2 new groups
        config.add_group()  # Group C
        config.add_group()  # Group D
        # Cancel the configuration
        config.cancel()

        self._assert_fields(
            config,
            name="Name of the Group Configuration",
            description="Description of the group configuration.",
            groups=["Group 0", "Group 1"])

    def test_group_configuration_validation(self):
        """
        Scenario: Ensure that validation of the group configuration works correctly.
        Given I have a course without group configurations
        And I create new group configuration with 2 default groups
        When I set only description and try to save
        Then I see error message "Group Configuration name is required."
        When I set a name
        And I delete the name of one of the groups and try to save
        Then I see error message "All groups must have a name"
        When I delete all the groups and try to save
        Then I see error message "There must be at least one group."
        When I add a group and try to save
        Then I see the group configuration is saved successfully
        """
        def try_to_save_and_verify_error_message(message):
            # Try to save
            config.save()
            # Verify that configuration is still in editing mode
            self.assertEqual(config.mode, 'edit')
            # Verify error message
            self.assertEqual(message, config.validation_message)

        self.page.visit()
        # Create new group configuration
        self.page.create_experiment_group_configuration()
        # Leave empty required field
        config = self.page.experiment_group_configurations[0]
        config.description = "Description of the group configuration."

        try_to_save_and_verify_error_message(
            "Group Configuration name is required.")

        # Set required field
        config.name = "Name of the Group Configuration"
        config.groups[1].name = ''
        try_to_save_and_verify_error_message("All groups must have a name.")
        config.groups[0].remove()
        config.groups[0].remove()
        try_to_save_and_verify_error_message(
            "There must be at least one group.")
        config.add_group()

        # Save the configuration
        config.save()

        self._assert_fields(
            config,
            name="Name of the Group Configuration",
            description="Description of the group configuration.",
            groups=["Group A"])

    def test_group_configuration_empty_usage(self):
        """
        Scenario: When group configuration is not used, ensure that the link to outline page works correctly.
        Given I have a course without group configurations
        And I create new group configuration with 2 default groups
        Then I see a link to the outline page
        When I click on the outline link
        Then I see the outline page
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, "Name", "Description.",
                            [Group("0", "Group A"),
                             Group("1", "Group B")]),
                    ],
                },
            })

        # Go to the Group Configuration Page and click on outline anchor
        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.toggle()
        config.click_outline_anchor()

        # Waiting for the page load and verify that we've landed on course outline page
        self.outline_page.wait_for_page()

    def test_group_configuration_non_empty_usage(self):
        """
        Scenario: When group configuration is used, ensure that the links to units using a group configuration work correctly.
        Given I have a course without group configurations
        And I create new group configuration with 2 default groups
        And I create a unit and assign the newly created group configuration
        And open the Group Configuration page
        Then I see a link to the newly created unit
        When I click on the unit link
        Then I see correct unit page
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, "Name", "Description.",
                            [Group("0", "Group A"),
                             Group("1", "Group B")]),
                    ],
                },
            })

        # Assign newly created group configuration to unit
        vertical = self.course_fixture.get_nested_xblocks(
            category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('split_test',
                              'Test Content Experiment',
                              metadata={'user_partition_id': 0}))
        unit = CourseOutlineUnit(self.browser, vertical.locator)

        # Go to the Group Configuration Page and click unit anchor
        self.page.visit()
        config = self.page.experiment_group_configurations[0]
        config.toggle()
        usage = config.usages[0]
        config.click_unit_anchor()

        unit = ContainerPage(self.browser, vertical.locator)
        # Waiting for the page load and verify that we've landed on the unit page
        unit.wait_for_page()

        self.assertIn(unit.name, usage)

    def test_can_delete_unused_group_configuration(self):
        """
        Scenario: Ensure that the user can delete unused group configuration.
        Given I have a course with 2 group configurations
        And I go to the Group Configuration page
        When I delete the Group Configuration with name "Configuration 1"
        Then I see that there is one Group Configuration
        When I edit the Group Configuration with name "Configuration 2"
        And I delete the Group Configuration with name "Configuration 2"
        Then I see that the are no Group Configurations
        """
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, 'Configuration 1',
                            'Description of the group configuration.',
                            [Group("0", 'Group 0'),
                             Group("1", 'Group 1')]),
                        create_user_partition_json(
                            1, 'Configuration 2',
                            'Second group configuration.', [
                                Group("0", 'Alpha'),
                                Group("1", 'Beta'),
                                Group("2", 'Gamma')
                            ])
                    ],
                },
            })
        self.page.visit()

        self.assertEqual(len(self.page.experiment_group_configurations), 2)
        config = self.page.experiment_group_configurations[1]
        # Delete first group configuration via detail view
        config.delete()
        self.assertEqual(len(self.page.experiment_group_configurations), 1)

        config = self.page.experiment_group_configurations[0]
        config.edit()
        self.assertFalse(config.delete_button_is_disabled)
        # Delete first group configuration via edit view
        config.delete()
        self.assertEqual(len(self.page.experiment_group_configurations), 0)

    def test_cannot_delete_used_group_configuration(self):
        """
        Scenario: Ensure that the user cannot delete unused group configuration.
        Given I have a course with group configuration that is used in the Content Experiment
        When I go to the Group Configuration page
        Then I do not see delete button and I see a note about that
        When I edit the Group Configuration
        Then I do not see delete button and I see the note about that
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, "Name", "Description.",
                            [Group("0", "Group A"),
                             Group("1", "Group B")])
                    ],
                },
            })
        vertical = self.course_fixture.get_nested_xblocks(
            category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('split_test',
                              'Test Content Experiment',
                              metadata={'user_partition_id': 0}))
        # Go to the Group Configuration Page and click unit anchor
        self.page.visit()

        config = self.page.experiment_group_configurations[0]
        self.assertTrue(config.delete_button_is_disabled)
        self.assertIn('Cannot delete when in use by an experiment',
                      config.delete_note)

        config.edit()
        self.assertTrue(config.delete_button_is_disabled)
        self.assertIn('Cannot delete when in use by an experiment',
                      config.delete_note)

    def test_easy_access_from_experiment(self):
        """
        Scenario: When a Content Experiment uses a Group Configuration,
        ensure that the link to that Group Configuration works correctly.

        Given I have a course with two Group Configurations
        And Content Experiment is assigned to one Group Configuration
        Then I see a link to Group Configuration
        When I click on the Group Configuration link
        Then I see the Group Configurations page
        And I see that appropriate Group Configuration is expanded.
        """
        # Create a new group configurations
        self.course_fixture._update_xblock(
            self.course_fixture._course_location, {
                "metadata": {
                    u"user_partitions": [
                        create_user_partition_json(
                            0, "Name", "Description.",
                            [Group("0", "Group A"),
                             Group("1", "Group B")]),
                        create_user_partition_json(
                            1, 'Name of second Group Configuration',
                            'Second group configuration.', [
                                Group("0", 'Alpha'),
                                Group("1", 'Beta'),
                                Group("2", 'Gamma')
                            ]),
                    ],
                },
            })

        # Assign newly created group configuration to unit
        vertical = self.course_fixture.get_nested_xblocks(
            category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('split_test',
                              'Test Content Experiment',
                              metadata={'user_partition_id': 1}))

        unit = ContainerPage(self.browser, vertical.locator)
        unit.visit()
        experiment = unit.xblocks[0]

        group_configuration_link_name = experiment.group_configuration_link_name

        experiment.go_to_group_configuration_page()
        self.page.wait_for_page()

        # Appropriate Group Configuration is expanded.
        self.assertFalse(
            self.page.experiment_group_configurations[0].is_expanded)
        self.assertTrue(
            self.page.experiment_group_configurations[1].is_expanded)

        self.assertEqual(group_configuration_link_name,
                         self.page.experiment_group_configurations[1].name)

    def test_details_error_validation_message(self):
        """
        Scenario: When a Content Experiment uses a Group Configuration, ensure
        that an error validation message appears if necessary.

        Given I have a course with a Group Configuration containing two Groups
        And a Content Experiment is assigned to that Group Configuration
        When I go to the Group Configuration Page
        Then I do not see a error icon and message in the Group Configuration details view.
        When I add a Group
        Then I see an error icon and message in the Group Configuration details view
        """

        # Create group configuration and associated experiment
        config, _ = self.create_group_configuration_experiment(
            [Group("0", "Group A"),
             Group("1", "Group B")], True)

        # Display details view
        config.toggle()
        # Check that error icon and message are not present
        self.assertFalse(config.details_error_icon_is_present)
        self.assertFalse(config.details_message_is_present)

        # Add a group
        config.toggle()
        config.edit()
        config.add_group()
        config.save()

        # Display details view
        config.toggle()
        # Check that error icon and message are present
        self.assertTrue(config.details_error_icon_is_present)
        self.assertTrue(config.details_message_is_present)
        self.assertIn(
            "This content experiment has issues that affect content visibility.",
            config.details_message_text)

    def test_details_warning_validation_message(self):
        """
        Scenario: When a Content Experiment uses a Group Configuration, ensure
        that a warning validation message appears if necessary.

        Given I have a course with a Group Configuration containing three Groups
        And a Content Experiment is assigned to that Group Configuration
        When I go to the Group Configuration Page
        Then I do not see a warning icon and message in the Group Configuration details view.
        When I remove a Group
        Then I see a warning icon and message in the Group Configuration details view
        """

        # Create group configuration and associated experiment
        config, _ = self.create_group_configuration_experiment([
            Group("0", "Group A"),
            Group("1", "Group B"),
            Group("2", "Group C")
        ], True)

        # Display details view
        config.toggle()
        # Check that warning icon and message are not present
        self.assertFalse(config.details_warning_icon_is_present)
        self.assertFalse(config.details_message_is_present)

        # Remove a group
        config.toggle()
        config.edit()
        config.groups[2].remove()
        config.save()

        # Display details view
        config.toggle()
        # Check that warning icon and message are present
        self.assertTrue(config.details_warning_icon_is_present)
        self.assertTrue(config.details_message_is_present)
        self.assertIn(
            "This content experiment has issues that affect content visibility.",
            config.details_message_text)

    def test_edit_warning_message_empty_usage(self):
        """
        Scenario: When a Group Configuration is not used, ensure that there are no warning icon and message.

        Given I have a course with a Group Configuration containing two Groups
        When I edit the Group Configuration
        Then I do not see a warning icon and message
        """

        # Create a group configuration with no associated experiment and display edit view
        config = self.create_group_configuration_experiment(
            [Group("0", "Group A"),
             Group("1", "Group B")], False)
        config.edit()
        # Check that warning icon and message are not present
        self.assertFalse(config.edit_warning_icon_is_present)
        self.assertFalse(config.edit_warning_message_is_present)

    def test_edit_warning_message_non_empty_usage(self):
        """
        Scenario: When a Group Configuration is used, ensure that there are a warning icon and message.

        Given I have a course with a Group Configuration containing two Groups
        When I edit the Group Configuration
        Then I see a warning icon and message
        """

        # Create a group configuration with an associated experiment and display edit view
        config, _ = self.create_group_configuration_experiment(
            [Group("0", "Group A"),
             Group("1", "Group B")], True)
        config.edit()
        # Check that warning icon and message are present
        self.assertTrue(config.edit_warning_icon_is_present)
        self.assertTrue(config.edit_warning_message_is_present)
        self.assertIn(
            "This configuration is currently used in content experiments. If you make changes to the groups, you may need to edit those experiments.",
            config.edit_warning_message_text)

    def publish_unit_and_verify_groups_in_lms(self,
                                              courseware_page,
                                              group_names,
                                              publish=True):
        """
        Publish first unit in LMS and verify that Courseware page has given Groups
        """
        self.publish_unit_in_lms_and_view(courseware_page, publish)
        self.assertEqual(u'split_test',
                         courseware_page.xblock_component_type())
        self.assertTrue(
            courseware_page.q(css=".split-test-select").is_present())
        rendered_group_names = self.get_select_options(
            page=courseware_page, selector=".split-test-select")
        self.assertListEqual(group_names, rendered_group_names)

    def test_split_test_LMS_staff_view(self):
        """
        Scenario: Ensure that split test is correctly rendered in LMS staff mode as it is
                  and after inactive group removal.

        Given I have a course with group configurations and split test that assigned to first group configuration
        Then I publish split test and view it in LMS in staff view
        And it is rendered correctly
        Then I go to group configuration and delete group
        Then I publish split test and view it in LMS in staff view
        And it is rendered correctly
        Then I go to split test and delete inactive vertical
        Then I publish unit and view unit in LMS in staff view
        And it is rendered correctly
        """

        config, split_test = self.create_group_configuration_experiment([
            Group("0", "Group A"),
            Group("1", "Group B"),
            Group("2", "Group C")
        ], True)
        container = ContainerPage(self.browser, split_test.locator)

        # render in LMS correctly
        courseware_page = CoursewarePage(self.browser, self.course_id)
        self.publish_unit_and_verify_groups_in_lms(
            courseware_page, [u'Group A', u'Group B', u'Group C'])

        # I go to group configuration and delete group
        self.page.visit()
        self.page.q(css='.group-toggle').first.click()
        config.edit()
        config.groups[2].remove()
        config.save()
        self.page.q(css='.group-toggle').first.click()
        self._assert_fields(config,
                            name="Name",
                            description="Description",
                            groups=["Group A", "Group B"])
        self.browser.close()
        self.browser.switch_to_window(self.browser.window_handles[0])

        # render in LMS to see how inactive vertical is rendered
        self.publish_unit_and_verify_groups_in_lms(
            courseware_page,
            [u'Group A', u'Group B', u'Group ID 2 (inactive)'],
            publish=False)

        self.browser.close()
        self.browser.switch_to_window(self.browser.window_handles[0])

        # I go to split test and delete inactive vertical
        container.visit()
        container.delete(0)

        # render in LMS again
        self.publish_unit_and_verify_groups_in_lms(courseware_page,
                                                   [u'Group A', u'Group B'])
class ContentGroupConfigurationTest(StudioCourseTest):
    """
    Tests for content groups in the Group Configurations Page.
    There are tests for the experiment groups in test_studio_split_test.
    """
    def setUp(self):
        super(ContentGroupConfigurationTest, self).setUp()
        self.group_configurations_page = GroupConfigurationsPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

    def populate_course_fixture(self, course_fixture):
        """
        Populates test course with chapter, sequential, and 1 problems.
        The problem is visible only to Group "alpha".
        """
        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
                    XBlockFixtureDesc('vertical', 'Test Unit')
                )
            )
        )

    def create_and_verify_content_group(self, name, existing_groups):
        """
        Creates a new content group and verifies that it was properly created.
        """
        self.assertEqual(existing_groups, len(self.group_configurations_page.content_groups))
        if existing_groups == 0:
            self.group_configurations_page.create_first_content_group()
        else:
            self.group_configurations_page.add_content_group()
        config = self.group_configurations_page.content_groups[existing_groups]
        config.name = name
        # Save the content group
        self.assertEqual(config.get_text('.action-primary'), "Create")
        self.assertFalse(config.delete_button_is_present)
        config.save()
        self.assertIn(name, config.name)
        return config

    def test_no_content_groups_by_default(self):
        """
        Scenario: Ensure that message telling me to create a new content group is
            shown when no content groups exist.
        Given I have a course without content groups
        When I go to the Group Configuration page in Studio
        Then I see "You have not created any content groups yet." message
        """
        self.group_configurations_page.visit()
        self.assertTrue(self.group_configurations_page.no_content_groups_message_is_present)
        self.assertIn(
            "You have not created any content groups yet.",
            self.group_configurations_page.no_content_groups_message_text
        )

    def test_can_create_and_edit_content_groups(self):
        """
        Scenario: Ensure that the content groups can be created and edited correctly.
        Given I have a course without content groups
        When I click button 'Add your first Content Group'
        And I set new the name and click the button 'Create'
        Then I see the new content is added and has correct data
        And I click 'New Content Group' button
        And I set the name and click the button 'Create'
        Then I see the second content group is added and has correct data
        When I edit the second content group
        And I change the name and click the button 'Save'
        Then I see the second content group is saved successfully and has the new name
        """
        self.group_configurations_page.visit()
        self.create_and_verify_content_group("New Content Group", 0)
        second_config = self.create_and_verify_content_group("Second Content Group", 1)

        # Edit the second content group
        second_config.edit()
        second_config.name = "Updated Second Content Group"
        self.assertEqual(second_config.get_text('.action-primary'), "Save")
        second_config.save()

        self.assertIn("Updated Second Content Group", second_config.name)

    def test_cannot_delete_used_content_group(self):
        """
        Scenario: Ensure that the user cannot delete used content group.
        Given I have a course with 1 Content Group
        And I go to the Group Configuration page
        When I try to delete the Content Group with name "New Content Group"
        Then I see the delete button is disabled.
        """
        self.course_fixture._update_xblock(self.course_fixture._course_location, {
            "metadata": {
                u"user_partitions": [
                    create_user_partition_json(
                        0,
                        'Configuration alpha,',
                        'Content Group Partition',
                        [Group("0", 'alpha')],
                        scheme="cohort"
                    )
                ],
            },
        })
        problem_data = dedent("""
            <problem markdown="Simple Problem" max_attempts="" weight="">
              <p>Choose Yes.</p>
              <choiceresponse>
                <checkboxgroup>
                  <choice correct="true">Yes</choice>
                </checkboxgroup>
              </choiceresponse>
            </problem>
        """)
        vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0]
        self.course_fixture.create_xblock(
            vertical.locator,
            XBlockFixtureDesc('problem', "VISIBLE TO ALPHA", data=problem_data, metadata={"group_access": {0: [0]}}),
        )
        self.group_configurations_page.visit()
        config = self.group_configurations_page.content_groups[0]
        self.assertTrue(config.delete_button_is_disabled)

    def test_can_delete_unused_content_group(self):
        """
        Scenario: Ensure that the user can delete unused content group.
        Given I have a course with 1 Content Group
        And I go to the Group Configuration page
        When I delete the Content Group with name "New Content Group"
        Then I see that there is no Content Group
        When I refresh the page
        Then I see that the content group has been deleted
        """
        self.group_configurations_page.visit()
        config = self.create_and_verify_content_group("New Content Group", 0)
        self.assertTrue(config.delete_button_is_present)

        self.assertEqual(len(self.group_configurations_page.content_groups), 1)

        # Delete content group
        config.delete()
        self.assertEqual(len(self.group_configurations_page.content_groups), 0)

        self.group_configurations_page.visit()
        self.assertEqual(len(self.group_configurations_page.content_groups), 0)

    def test_must_supply_name(self):
        """
        Scenario: Ensure that validation of the content group works correctly.
        Given I have a course without content groups
        And I create new content group without specifying a name click the button 'Create'
        Then I see error message "Content Group name is required."
        When I set a name and click the button 'Create'
        Then I see the content group is saved successfully
        """
        self.group_configurations_page.visit()
        self.group_configurations_page.create_first_content_group()
        config = self.group_configurations_page.content_groups[0]
        config.save()
        self.assertEqual(config.mode, 'edit')
        self.assertEqual("Group name is required", config.validation_message)
        config.name = "Content Group Name"
        config.save()
        self.assertIn("Content Group Name", config.name)

    def test_can_cancel_creation_of_content_group(self):
        """
        Scenario: Ensure that creation of a content group can be canceled correctly.
        Given I have a course without content groups
        When I click button 'Add your first Content Group'
        And I set new the name and click the button 'Cancel'
        Then I see that there is no content groups in the course
        """
        self.group_configurations_page.visit()
        self.group_configurations_page.create_first_content_group()
        config = self.group_configurations_page.content_groups[0]
        config.name = "Content Group"
        config.cancel()
        self.assertEqual(0, len(self.group_configurations_page.content_groups))

    def test_content_group_empty_usage(self):
        """
        Scenario: When content group is not used, ensure that the link to outline page works correctly.
        Given I have a course without content group
        And I create new content group
        Then I see a link to the outline page
        When I click on the outline link
        Then I see the outline page
        """
        self.group_configurations_page.visit()
        config = self.create_and_verify_content_group("New Content Group", 0)
        config.toggle()
        config.click_outline_anchor()

        # Waiting for the page load and verify that we've landed on course outline page
        self.outline_page.wait_for_page()