From 79c5137a6858bfdf7923d2d9414d8dff541dfab2 Mon Sep 17 00:00:00 2001 From: cahrens Date: Tue, 30 May 2017 17:15:35 -0400 Subject: [PATCH] Bok choy tests for division scheme. EDUCATOR-424 --- .../pages/lms/instructor_dashboard.py | 30 ++- .../acceptance/tests/discussion/helpers.py | 20 +- .../tests/discussion/test_cohorts.py | 1 + .../discussion/test_discussion_management.py | 250 +++++++++++++++--- .../test_lms_cohorted_courseware_search.py | 13 +- .../acceptance/tests/lms/test_lms_help.py | 12 +- .../tests/test_cohorted_courseware.py | 13 +- 7 files changed, 257 insertions(+), 82 deletions(-) diff --git a/common/test/acceptance/pages/lms/instructor_dashboard.py b/common/test/acceptance/pages/lms/instructor_dashboard.py index 077c7d02f2..c5c3f4092e 100644 --- a/common/test/acceptance/pages/lms/instructor_dashboard.py +++ b/common/test/acceptance/pages/lms/instructor_dashboard.py @@ -263,10 +263,6 @@ class CohortManagementSection(PageObject): no_content_group_button_css = '.cohort-management-details-association-course input.radio-no' select_content_group_button_css = '.cohort-management-details-association-course input.radio-yes' assignment_type_buttons_css = '.cohort-management-assignment-type-settings input' - discussion_form_selectors = { - 'course-wide': '.cohort-course-wide-discussions-form', - 'inline': '.cohort-inline-discussions-form' - } def get_cohort_help_element_and_click_help(self): """ @@ -689,9 +685,14 @@ class DiscussionManagementSection(PageObject): discussion_form_selectors = { 'course-wide': '.cohort-course-wide-discussions-form', - 'inline': '.cohort-inline-discussions-form' + 'inline': '.cohort-inline-discussions-form', + 'scheme': '.division-scheme-container', } + NOT_DIVIDED_SCHEME = "none" + COHORT_SCHEME = "cohort" + ENROLLMENT_TRACK_SCHEME = "enrollment_track" + def is_browser_on_page(self): return self.q(css=self.discussion_form_selectors['course-wide']).present @@ -801,6 +802,25 @@ class DiscussionManagementSection(PageObject): """ return self.q(css=self._bounded_selector('.check-discussion-category:checked')).is_present() + def get_selected_scheme(self): + """ + Returns the ID of the selected discussion division scheme + ("NOT_DIVIDED_SCHEME", "COHORT_SCHEME", or "ENROLLMENT_TRACK_SCHEME)". + """ + return self.q(css=self._bounded_selector('.division-scheme:checked')).first.attrs('id')[0] + + def select_division_scheme(self, scheme): + """ + Selects the radio button associated with the specified division scheme. + """ + self.q(css=self._bounded_selector("input#%s" % scheme)).first.click() + + def division_scheme_visible(self, scheme): + """ + Returns whether or not the specified scheme is visible as an option. + """ + return self.q(css=self._bounded_selector("input#%s" % scheme)).visible + class MembershipPageAutoEnrollSection(PageObject): """ diff --git a/common/test/acceptance/tests/discussion/helpers.py b/common/test/acceptance/tests/discussion/helpers.py index 3e216dd4a4..48fa29c157 100644 --- a/common/test/acceptance/tests/discussion/helpers.py +++ b/common/test/acceptance/tests/discussion/helpers.py @@ -76,22 +76,26 @@ class CohortTestMixin(object): def enable_cohorting(self, course_fixture): """ - enables cohorts and always_divide_inline_discussions for the current course fixture. + Enables cohorting for the specified course fixture. """ - url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access - discussions_url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/discussions/settings' # pylint: disable=protected-access - + url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' data = json.dumps({'is_cohorted': True}) - discussions_data = json.dumps({'always_divide_inline_discussions': True}) - response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) + self.assertTrue(response.ok, "Failed to enable cohorts") + + def enable_always_divide_inline_discussions(self, course_fixture): + """ + Enables "always_divide_inline_discussions" (but does not enabling cohorting). + """ + discussions_url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/discussions/settings' + discussions_data = json.dumps({'always_divide_inline_discussions': True}) course_fixture.session.patch(discussions_url, data=discussions_data, headers=course_fixture.headers) def disable_cohorting(self, course_fixture): """ - Disables cohorting for the current course fixture. + Disables cohorting for the specified course fixture. """ - url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access + url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' data = json.dumps({'is_cohorted': False}) response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) self.assertTrue(response.ok, "Failed to disable cohorts") diff --git a/common/test/acceptance/tests/discussion/test_cohorts.py b/common/test/acceptance/tests/discussion/test_cohorts.py index 8ed7b518d2..a60420defb 100644 --- a/common/test/acceptance/tests/discussion/test_cohorts.py +++ b/common/test/acceptance/tests/discussion/test_cohorts.py @@ -47,6 +47,7 @@ class CohortedDiscussionTestMixin(BaseDiscussionMixin, CohortTestMixin): # Enable cohorts and verify that the post shows to cohort only. self.enable_cohorting(self.course_fixture) + self.enable_always_divide_inline_discussions(self.course_fixture) self.refresh_thread_page(self.thread_id) self.assertEquals( self.thread_page.get_group_visibility_label(), diff --git a/common/test/acceptance/tests/discussion/test_discussion_management.py b/common/test/acceptance/tests/discussion/test_discussion_management.py index f49109bc8f..8ae8552453 100644 --- a/common/test/acceptance/tests/discussion/test_discussion_management.py +++ b/common/test/acceptance/tests/discussion/test_discussion_management.py @@ -4,25 +4,26 @@ End-to-end tests related to the divided discussion management on the LMS Instruc """ from nose.plugins.attrib import attr -from common.test.acceptance.tests.discussion.helpers import CohortTestMixin +from common.test.acceptance.tests.discussion.helpers import BaseDiscussionMixin, CohortTestMixin from common.test.acceptance.tests.helpers import UniqueCourseTest from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc from common.test.acceptance.pages.lms.auto_auth import AutoAuthPage +from common.test.acceptance.pages.lms.discussion import DiscussionTabSingleThreadPage from common.test.acceptance.pages.lms.instructor_dashboard import InstructorDashboardPage +from common.test.acceptance.pages.common.utils import add_enrollment_course_modes import uuid -@attr(shard=6) -class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): +class BaseDividedDiscussionTest(UniqueCourseTest, CohortTestMixin): """ - Tests for dividing the inline and course-wide discussion topics. + Base class for tests related to divided discussions. """ def setUp(self): """ Set up a discussion topic """ - super(DividedDiscussionTopicsTest, self).setUp() + super(BaseDividedDiscussionTest, self).setUp() self.discussion_id = "test_discussion_{}".format(uuid.uuid4().hex) self.course_fixture = CourseFixture(**self.course_info).add_children( @@ -59,24 +60,53 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): self.course_wide_key = 'course-wide' self.inline_key = 'inline' + self.scheme_key = 'scheme' - def divided_discussion_topics_are_visible(self): + def check_discussion_topic_visibility(self, visible=True): """ Assert that discussion topics are visible with appropriate content. """ - self.assertTrue(self.discussion_management_page.discussion_topics_visible()) + self.assertEqual(visible, self.discussion_management_page.discussion_topics_visible()) - self.assertEqual( - "Course-Wide Discussion Topics", - self.discussion_management_page.divided_discussion_heading_is_visible(self.course_wide_key) - ) - self.assertTrue(self.discussion_management_page.is_save_button_disabled(self.course_wide_key)) + if visible: + self.assertEqual( + "Course-Wide Discussion Topics", + self.discussion_management_page.divided_discussion_heading_is_visible(self.course_wide_key) + ) + self.assertTrue(self.discussion_management_page.is_save_button_disabled(self.course_wide_key)) - self.assertEqual( - "Content-Specific Discussion Topics", - self.discussion_management_page.divided_discussion_heading_is_visible(self.inline_key) - ) - self.assertTrue(self.discussion_management_page.is_save_button_disabled(self.inline_key)) + self.assertEqual( + "Content-Specific Discussion Topics", + self.discussion_management_page.divided_discussion_heading_is_visible(self.inline_key) + ) + self.assertTrue(self.discussion_management_page.is_save_button_disabled(self.inline_key)) + + def reload_page(self, topics_visible=True): + """ + Refresh the page, then verify if the discussion topics are visible on the discussion + management instructor dashboard tab. + """ + self.browser.refresh() + self.discussion_management_page.wait_for_page() + + self.instructor_dashboard_page.select_discussion_management() + self.discussion_management_page.wait_for_page() + + self.check_discussion_topic_visibility(topics_visible) + + def verify_save_confirmation_message(self, key): + """ + Verify that the save confirmation message for the specified portion of the page is visible. + """ + confirmation_message = self.discussion_management_page.get_divide_discussions_message(key=key) + self.assertEqual("Your changes have been saved.", confirmation_message) + + +@attr(shard=6) +class DividedDiscussionTopicsTest(BaseDividedDiscussionTest): + """ + Tests for dividing the inline and course-wide discussion topics. + """ def save_and_verify_discussion_topics(self, key): """ @@ -86,24 +116,11 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): self.discussion_management_page.save_discussion_topics(key) # verifies that changes saved successfully. - confirmation_message = self.discussion_management_page.get_divide_discussions_message(key=key) - self.assertEqual("Your changes have been saved.", confirmation_message) + self.verify_save_confirmation_message(key) # save button disabled again. self.assertTrue(self.discussion_management_page.is_save_button_disabled(key)) - def reload_page(self): - """ - Refresh the page. - """ - self.browser.refresh() - self.discussion_management_page.wait_for_page() - - self.instructor_dashboard_page.select_discussion_management() - self.discussion_management_page.wait_for_page() - - self.divided_discussion_topics_are_visible() - def verify_discussion_topics_after_reload(self, key, divided_topics): """ Verifies the changed topics. @@ -124,7 +141,7 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): When I reload the page Then I see the discussion topic selected """ - self.divided_discussion_topics_are_visible() + self.check_discussion_topic_visibility() divided_topics_before = self.discussion_management_page.get_divided_topics_count(self.course_wide_key) self.discussion_management_page.select_discussion_topic(self.course_wide_key) @@ -151,7 +168,7 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): And I reload the page Then I see the always_divide_inline_topics option enabled """ - self.divided_discussion_topics_are_visible() + self.check_discussion_topic_visibility() # enable always inline discussion topics and save the change self.discussion_management_page.select_always_inline_discussion() @@ -175,7 +192,7 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): And I reload the page Then I see the divide_some_inline_topics option enabled """ - self.divided_discussion_topics_are_visible() + self.check_discussion_topic_visibility() # By default always inline discussion topics is False. Enable it (and reload the page). self.assertFalse(self.discussion_management_page.always_inline_discussion_selected()) self.discussion_management_page.select_always_inline_discussion() @@ -207,7 +224,7 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): When I reload the page Then I see the discussion topic selected """ - self.divided_discussion_topics_are_visible() + self.check_discussion_topic_visibility() divided_topics_before = self.discussion_management_page.get_divided_topics_count(self.inline_key) # check the discussion topic. @@ -234,7 +251,7 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): Then I see enabled saved button Then I see parent category to be checked. """ - self.divided_discussion_topics_are_visible() + self.check_discussion_topic_visibility() # category should not be selected. self.assertFalse(self.discussion_management_page.is_category_selected()) @@ -255,7 +272,7 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): Then I see enabled saved button Then I see parent category to be deselected. """ - self.divided_discussion_topics_are_visible() + self.check_discussion_topic_visibility() # category should not be selected. self.assertFalse(self.discussion_management_page.is_category_selected()) @@ -271,3 +288,162 @@ class DividedDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin): # category should not be selected. self.assertFalse(self.discussion_management_page.is_category_selected()) + + +@attr(shard=6) +class DivisionSchemeTest(BaseDividedDiscussionTest, BaseDiscussionMixin): + """ + Tests for changing the division scheme for Discussions. + """ + + def add_modes_and_view_discussion_mgmt_page(self, modes): + """ + Adds enrollment modes to the course, and then goes to the + discussion tab on the instructor dashboard. + """ + add_enrollment_course_modes(self.browser, self.course_id, modes) + self.view_discussion_management_page() + + def view_discussion_management_page(self): + """ + Go to the discussion tab on the instructor dashboard. + """ + self.instructor_dashboard_page.visit() + self.instructor_dashboard_page.select_discussion_management() + self.discussion_management_page.wait_for_page() + + def setup_thread_page(self, thread_id): + """ + This is called by BaseDiscussionMixin.setup_thread. + """ + self.thread_page = DiscussionTabSingleThreadPage( + self.browser, self.course_id, self.discussion_id, thread_id + ) + self.thread_page.visit() + + def test_not_divided_hides_discussion_topics(self): + """ + Tests that discussion topics are hidden iff discussion division is disabled. + """ + # Initially "Cohort" is the selected scheme. + self.assertTrue( + self.discussion_management_page.division_scheme_visible(self.discussion_management_page.COHORT_SCHEME) + ) + self.assertEqual( + self.discussion_management_page.COHORT_SCHEME, + self.discussion_management_page.get_selected_scheme() + ) + self.check_discussion_topic_visibility(visible=True) + + self.discussion_management_page.select_division_scheme(self.discussion_management_page.NOT_DIVIDED_SCHEME) + self.verify_save_confirmation_message(self.scheme_key) + self.check_discussion_topic_visibility(visible=False) + + # Reload the page and make sure that the change was persisted + self.reload_page(topics_visible=False) + self.assertTrue(self.discussion_management_page.division_scheme_visible( + self.discussion_management_page.COHORT_SCHEME) + ) + self.assertEqual( + self.discussion_management_page.NOT_DIVIDED_SCHEME, + self.discussion_management_page.get_selected_scheme() + ) + + # Select "cohort" again and make sure that the discussion topics appear. + self.discussion_management_page.select_division_scheme(self.discussion_management_page.COHORT_SCHEME) + self.verify_save_confirmation_message(self.scheme_key) + self.check_discussion_topic_visibility(visible=True) + + def test_disabling_cohorts(self): + """ + Test that disabling cohorts hides the cohort division scheme iff it is not the selected scheme + (even without reloading the page). + """ + # TODO: will be added as part of AJ's work. + pass + + def test_single_enrollment_mode(self): + """ + Test that the enrollment track scheme is not visible if there is a single enrollment mode. + """ + self.add_modes_and_view_discussion_mgmt_page(['audit']) + self.assertFalse( + self.discussion_management_page.division_scheme_visible( + self.discussion_management_page.ENROLLMENT_TRACK_SCHEME + ) + ) + + def test_radio_buttons_with_multiple_enrollment_modes(self): + """ + Test that the enrollment track scheme is visible if there are multiple enrollment tracks, + and that the selection can be persisted. + + Also verifies that the cohort division scheme is not presented if cohorts are disabled and cohorts + are not the selected division scheme. + """ + self.add_modes_and_view_discussion_mgmt_page(['audit', 'verified']) + self.assertTrue( + self.discussion_management_page.division_scheme_visible( + self.discussion_management_page.ENROLLMENT_TRACK_SCHEME + ) + ) + # And the cohort scheme is initially visible because it is selected (and cohorts are enabled). + self.assertTrue( + self.discussion_management_page.division_scheme_visible(self.discussion_management_page.COHORT_SCHEME) + ) + + self.discussion_management_page.select_division_scheme(self.discussion_management_page.ENROLLMENT_TRACK_SCHEME) + self.verify_save_confirmation_message(self.scheme_key) + self.check_discussion_topic_visibility(visible=True) + + # Also disable cohorts so we can verify that the cohort scheme choice goes away. + self.disable_cohorting(self.course_fixture) + + self.reload_page(topics_visible=True) + self.assertEqual( + self.discussion_management_page.ENROLLMENT_TRACK_SCHEME, + self.discussion_management_page.get_selected_scheme() + ) + # Verify that the cohort scheme is no longer visible as cohorts are disabled. + self.assertFalse( + self.discussion_management_page.division_scheme_visible(self.discussion_management_page.COHORT_SCHEME) + ) + + def test_enrollment_track_discussion_visibility_label(self): + """ + If enrollment tracks are the division scheme, verifies that discussion visibility labels + correctly render. + + Note that there are similar tests for cohorts in test_cohorts.py. + """ + def refresh_thread_page(): + self.browser.refresh() + self.thread_page.wait_for_page() + + # Make moderator for viewing all groups in discussions. + AutoAuthPage(self.browser, course_id=self.course_id, roles="Moderator", staff=True).visit() + + self.add_modes_and_view_discussion_mgmt_page(['audit', 'verified']) + self.discussion_management_page.select_division_scheme(self.discussion_management_page.ENROLLMENT_TRACK_SCHEME) + self.verify_save_confirmation_message(self.scheme_key) + # Set "always divide" as the thread we will be creating will be an inline thread, + # and this way the thread does not need to be explicitly divided. + self.enable_always_divide_inline_discussions(self.course_fixture) + + # Create a thread with group_id corresponding to the Audit enrollment mode. + # The Audit group ID is 1, and for the comment service group_id we negate it. + self.setup_thread(1, group_id=-1) + + refresh_thread_page() + self.assertEquals( + self.thread_page.get_group_visibility_label(), + "This post is visible only to {}.".format("Audit") + ) + + # Disable dividing discussions and verify that the post now shows as visible to everyone. + self.view_discussion_management_page() + self.discussion_management_page.select_division_scheme(self.discussion_management_page.NOT_DIVIDED_SCHEME) + self.verify_save_confirmation_message(self.scheme_key) + + self.thread_page.visit() + self.assertEquals(self.thread_page.get_group_visibility_label(), "This post is visible to everyone.") diff --git a/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py b/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py index 56365c5a58..dd699f7b5d 100644 --- a/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py +++ b/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py @@ -7,7 +7,6 @@ import uuid from nose.plugins.attrib import attr -from common.test.acceptance.fixtures import LMS_BASE_URL from common.test.acceptance.fixtures.course import XBlockFixtureDesc from common.test.acceptance.pages.common.auto_auth import AutoAuthPage from common.test.acceptance.pages.common.logout import LogoutPage @@ -19,10 +18,11 @@ from common.test.acceptance.pages.studio.overview import CourseOutlinePage as St from common.test.acceptance.pages.studio.settings_group_configurations import GroupConfigurationsPage from common.test.acceptance.tests.helpers import remove_file from common.test.acceptance.tests.studio.base_studio_test import ContainerBase +from common.test.acceptance.tests.discussion.helpers import CohortTestMixin @attr(shard=1) -class CoursewareSearchCohortTest(ContainerBase): +class CoursewareSearchCohortTest(ContainerBase, CohortTestMixin): """ Test courseware search. """ @@ -132,15 +132,6 @@ class CoursewareSearchCohortTest(ContainerBase): ) ) - def enable_cohorting(self, course_fixture): - """ - Enables cohorting for the current course. - """ - url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access - data = json.dumps({'is_cohorted': True}) - response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) - self.assertTrue(response.ok, "Failed to enable cohorts") - def create_content_groups(self): """ Creates two content groups in Studio Group Configurations Settings. diff --git a/common/test/acceptance/tests/lms/test_lms_help.py b/common/test/acceptance/tests/lms/test_lms_help.py index b0e8bf27b5..979a9b0445 100644 --- a/common/test/acceptance/tests/lms/test_lms_help.py +++ b/common/test/acceptance/tests/lms/test_lms_help.py @@ -10,9 +10,10 @@ from common.test.acceptance.pages.lms.instructor_dashboard import InstructorDash from common.test.acceptance.tests.helpers import assert_opened_help_link_is_correct, url_for_help from common.test.acceptance.tests.lms.test_lms_instructor_dashboard import BaseInstructorDashboardTest from common.test.acceptance.tests.studio.base_studio_test import ContainerBase +from common.test.acceptance.tests.discussion.helpers import CohortTestMixin -class TestCohortHelp(ContainerBase): +class TestCohortHelp(ContainerBase, CohortTestMixin): """ Tests help links in Cohort page """ @@ -74,15 +75,6 @@ class TestCohortHelp(ContainerBase): ) self.verify_help_link(href) - def enable_cohorting(self, course_fixture): - """ - Enables cohorting for the current course. - """ - url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access - data = json.dumps({'is_cohorted': True}) - response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) - self.assertTrue(response.ok, "Failed to enable cohorts") - class InstructorDashboardHelp(BaseInstructorDashboardTest): """ diff --git a/common/test/acceptance/tests/test_cohorted_courseware.py b/common/test/acceptance/tests/test_cohorted_courseware.py index acbc52ee86..d0509e987e 100644 --- a/common/test/acceptance/tests/test_cohorted_courseware.py +++ b/common/test/acceptance/tests/test_cohorted_courseware.py @@ -7,7 +7,6 @@ import json from bok_choy.page_object import XSS_INJECTION from nose.plugins.attrib import attr -from common.test.acceptance.fixtures import LMS_BASE_URL from common.test.acceptance.fixtures.course import XBlockFixtureDesc from common.test.acceptance.pages.common.auto_auth import AutoAuthPage from common.test.acceptance.pages.common.utils import add_enrollment_course_modes, enroll_user_track @@ -16,6 +15,7 @@ from common.test.acceptance.pages.lms.instructor_dashboard import InstructorDash from common.test.acceptance.pages.studio.component_editor import ComponentVisibilityEditorView from common.test.acceptance.pages.studio.settings_group_configurations import GroupConfigurationsPage from common.test.acceptance.tests.lms.test_lms_user_preview import verify_expected_problem_visibility +from common.test.acceptance.tests.discussion.helpers import CohortTestMixin from studio.base_studio_test import ContainerBase AUDIT_TRACK = "Audit" @@ -23,7 +23,7 @@ VERIFIED_TRACK = "Verified" @attr(shard=5) -class EndToEndCohortedCoursewareTest(ContainerBase): +class EndToEndCohortedCoursewareTest(ContainerBase, CohortTestMixin): """ End-to-end of cohorted courseware. """ @@ -113,15 +113,6 @@ class EndToEndCohortedCoursewareTest(ContainerBase): ) ) - def enable_cohorting(self, course_fixture): - """ - Enables cohorting for the current course. - """ - url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/settings' # pylint: disable=protected-access - data = json.dumps({'is_cohorted': True}) - response = course_fixture.session.patch(url, data=data, headers=course_fixture.headers) - self.assertTrue(response.ok, "Failed to enable cohorts") - def create_content_groups(self): """ Creates two content groups in Studio Group Configurations Settings.