From 6fbd86108ce07484ce95dcc0df5ee836c40f8ccd Mon Sep 17 00:00:00 2001 From: rabiaiftikhar Date: Wed, 24 Oct 2018 02:03:55 +0500 Subject: [PATCH] EDUCATOR-2303 allow learners to see gated banner before starting proctored or timed exam --- common/lib/xmodule/xmodule/seq_module.py | 34 ++++---- .../test/acceptance/pages/lms/courseware.py | 8 ++ .../acceptance/tests/lms/test_lms_gating.py | 82 +++++++++++++++++-- 3 files changed, 99 insertions(+), 25 deletions(-) diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index 2cd8d29114..d8e821c699 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -241,13 +241,23 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): context = context or {} self._capture_basic_metrics() banner_text = None - special_html_view = self._hidden_content_student_view(context) or self._special_exam_student_view() - if special_html_view: - masquerading_as_specific_student = context.get('specific_masquerade', False) - banner_text, special_html = special_html_view - if special_html and not masquerading_as_specific_student: - return Fragment(special_html) - return self._student_view(context, banner_text) + prereq_met = True + prereq_meta_info = {} + + if self._required_prereq(): + if self.runtime.user_is_staff: + banner_text = _('This subsection is unlocked for learners when they meet the prerequisite requirements.') + else: + # check if prerequisite has been met + prereq_met, prereq_meta_info = self._compute_is_prereq_met(True) + if prereq_met: + special_html_view = self._hidden_content_student_view(context) or self._special_exam_student_view() + if special_html_view: + masquerading_as_specific_student = context.get('specific_masquerade', False) + banner_text, special_html = special_html_view + if special_html and not masquerading_as_specific_student: + return Fragment(special_html) + return self._student_view(context, prereq_met, prereq_meta_info, banner_text) def _special_exam_student_view(self): """ @@ -299,7 +309,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): # NOTE (CCB): We default to true to maintain the behavior in place prior to allowing anonymous access access. return context.get('user_authenticated', True) - def _student_view(self, context, banner_text=None): + def _student_view(self, context, prereq_met, prereq_meta_info, banner_text=None): """ Returns the rendered student view of the content of this sequential. If banner_text is given, it is added to the @@ -307,15 +317,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): """ display_items = self.get_display_items() self._update_position(context, len(display_items)) - prereq_met = True - prereq_meta_info = {} - if self._required_prereq(): - if self.runtime.user_is_staff: - banner_text = _('This subsection is unlocked for learners when they meet the prerequisite requirements.') - else: - # check if prerequisite has been met - prereq_met, prereq_meta_info = self._compute_is_prereq_met(True) if prereq_met and not self._is_gate_fulfilled(): banner_text = _('This section is a prerequisite. You must complete this section in order to unlock additional content.') diff --git a/common/test/acceptance/pages/lms/courseware.py b/common/test/acceptance/pages/lms/courseware.py index cd1e71e781..6c035e98e2 100644 --- a/common/test/acceptance/pages/lms/courseware.py +++ b/common/test/acceptance/pages/lms/courseware.py @@ -325,6 +325,14 @@ class CoursewarePage(CoursePage, CompletionOnViewMixin): bookmarks_page = BookmarksPage(self.browser, self.course_id) bookmarks_page.visit() + def is_gating_banner_visible(self): + """ + Check if the gated banner for locked content is visible. + """ + return self.q(css='.problem-header').is_present() \ + and self.q(css='.btn-brand').text[0] == u'Go To Prerequisite Section' \ + and self.q(css='.problem-header').text[0] == u'Content Locked' + class CoursewareSequentialTabPage(CoursePage): """ diff --git a/common/test/acceptance/tests/lms/test_lms_gating.py b/common/test/acceptance/tests/lms/test_lms_gating.py index b90d6e7b96..f176a19508 100644 --- a/common/test/acceptance/tests/lms/test_lms_gating.py +++ b/common/test/acceptance/tests/lms/test_lms_gating.py @@ -60,7 +60,7 @@ class GatingTest(UniqueCourseTest): self.course_info['display_name'] ) course_fixture.add_advanced_settings({ - "enable_subsection_gating": {"value": "true"} + "enable_subsection_gating": {"value": "true"}, 'enable_proctored_exams': {"value": "true"} }) course_fixture.add_children( @@ -70,7 +70,11 @@ class GatingTest(UniqueCourseTest): ), XBlockFixtureDesc('sequential', 'Test Subsection 2').add_children( XBlockFixtureDesc('problem', 'Test Problem 2') - ) + ), + XBlockFixtureDesc('sequential', 'Test Subsection 3').add_children( + XBlockFixtureDesc('problem', 'Test Problem 3') + ), + ) ).install() @@ -95,16 +99,16 @@ class GatingTest(UniqueCourseTest): self.studio_course_outline.select_advanced_tab(desired_item='gated_content') self.studio_course_outline.make_gating_prerequisite() - def _setup_gated_subsection(self): + def _setup_gated_subsection(self, subsection_index=1): """ - Gate the second subsection on the first subsection + Gate the given indexed subsection on the first subsection """ # Login as staff self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) # Gate the second subsection based on the score achieved in the first subsection self.studio_course_outline.visit() - self.studio_course_outline.open_subsection_settings_dialog(1) + self.studio_course_outline.open_subsection_settings_dialog(subsection_index) self.studio_course_outline.select_advanced_tab(desired_item='gated_content') self.studio_course_outline.add_prerequisite_to_subsection("80", "") @@ -164,13 +168,13 @@ class GatingTest(UniqueCourseTest): self._auto_auth(self.STUDENT_USERNAME, self.STUDENT_EMAIL, False) self.course_home_page.visit() - self.assertEqual(self.course_home_page.outline.num_subsections, 2) + self.assertEqual(self.course_home_page.outline.num_subsections, 3) # Fulfill prerequisite and verify that gated subsection is shown self.courseware_page.visit() self._fulfill_prerequisite() self.course_home_page.visit() - self.assertEqual(self.course_home_page.outline.num_subsections, 2) + self.assertEqual(self.course_home_page.outline.num_subsections, 3) def test_gated_subsection_in_lms_for_staff(self): """ @@ -190,7 +194,7 @@ class GatingTest(UniqueCourseTest): self.course_home_page.visit() self.assertEqual(self.course_home_page.preview.staff_view_mode, 'Staff') - self.assertEqual(self.course_home_page.outline.num_subsections, 2) + self.assertEqual(self.course_home_page.outline.num_subsections, 3) # Click on gated section and check for banner self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 2') @@ -204,8 +208,68 @@ class GatingTest(UniqueCourseTest): self.course_home_page.visit() self.course_home_page.preview.set_staff_view_mode('Learner') self.course_home_page.wait_for_page() - self.assertEqual(self.course_home_page.outline.num_subsections, 2) + self.assertEqual(self.course_home_page.outline.num_subsections, 3) self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 1') self.courseware_page.wait_for_page() # banner displayed informing section is a prereq self.assertTrue(self.courseware_page.has_banner()) + + def test_gated_banner_before_special_exam(self): + """ + When a subsection with a prereq is a special + exam, show the gating banner before starting + the special exam. + + Setup the course with a subsection having pre-req + Subsection with pre-req is a special exam + Go the LMS course outline page + Click the special exam subsection + The gated banner asking for completing + prereqs should be visible + Go to the required subsection + Fulfill the requirements + Visit the special exam subsection again + The gated banner is not visible anymore + and user can start the special exam + """ + + self._setup_prereq() + + # Gating subsection 1 and making it a timed exam + self._setup_gated_subsection() + self.studio_course_outline.open_subsection_settings_dialog(1) + self.studio_course_outline.select_advanced_tab() + self.studio_course_outline.make_exam_timed() + + # Gating subsection 2 and making it a proctored exam + self._setup_gated_subsection(2) + self.studio_course_outline.open_subsection_settings_dialog(2) + self.studio_course_outline.select_advanced_tab() + self.studio_course_outline.make_exam_proctored() + + self._auto_auth(self.STUDENT_USERNAME, self.STUDENT_EMAIL, False) + self.course_home_page.visit() + + # Test gating banner before starting timed exam + self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 2') + self.assertTrue(self.courseware_page.is_gating_banner_visible()) + + # Test gating banner before proctored exams + self.course_home_page.visit() + self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 3') + self.assertTrue(self.courseware_page.is_gating_banner_visible()) + + # Fulfill requirements + self.course_home_page.visit() + self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 1') + self._fulfill_prerequisite() + + # Banner is not visible anymore on timed exam sub-section + self.course_home_page.visit() + self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 2') + self.assertFalse(self.courseware_page.is_gating_banner_visible()) + + # Banner is not visible on proctored exam subsection + self.course_home_page.visit() + self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 3') + self.assertFalse(self.courseware_page.is_gating_banner_visible())