예제 #1
0
class StudioSubsectionSettingsA11yTest(StudioCourseTest):
    """
    Class to test accessibility on the subsection settings modals.
    """
    def setUp(self):  # pylint: disable=arguments-differ
        browser = os.environ.get('SELENIUM_BROWSER', 'firefox')

        # This test will fail if run using phantomjs < 2.0, due to an issue with bind()
        # See https://github.com/ariya/phantomjs/issues/10522 for details.

        # The course_outline uses this function, and as such will not fully load when run
        # under phantomjs 1.9.8. So, to prevent this test from timing out at course_outline.visit(),
        # force the use of firefox vs the standard a11y test usage of phantomjs 1.9.8.

        # TODO: remove this block once https://openedx.atlassian.net/browse/TE-1047 is resolved.
        if browser == 'phantomjs':
            browser = 'firefox'

        with patch.dict(os.environ, {'SELENIUM_BROWSER': browser}):
            super(StudioSubsectionSettingsA11yTest, self).setUp(is_staff=True)

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

    def populate_course_fixture(self, course_fixture):
        course_fixture.add_advanced_settings(
            {"enable_proctored_exams": {
                "value": "true"
            }})

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
                XBlockFixtureDesc('sequential',
                                  'Test Subsection 1').add_children(
                                      XBlockFixtureDesc(
                                          'problem', 'Test Problem 1'))))

    def test_special_exams_menu_a11y(self):
        """
        Given that I am a staff member
        And I am editing settings on the special exams menu
        Then that menu is accessible
        """
        self.course_outline.visit()
        self.course_outline.open_subsection_settings_dialog()
        self.course_outline.select_advanced_tab()

        self.course_outline.a11y_audit.config.set_rules({
            "ignore": [
                'section',  # TODO: AC-491
            ],
        })
        # limit the scope of the audit to the special exams tab on the modal dialog
        self.course_outline.a11y_audit.config.set_scope(
            include=['section.edit-settings-timed-examination'])
        self.course_outline.a11y_audit.check_for_accessibility_errors()
class StudioSubsectionSettingsA11yTest(StudioCourseTest):
    """
    Class to test accessibility on the subsection settings modals.
    """

    def setUp(self):  # pylint: disable=arguments-differ
        browser = os.environ.get('SELENIUM_BROWSER', 'firefox')

        # This test will fail if run using phantomjs < 2.0, due to an issue with bind()
        # See https://github.com/ariya/phantomjs/issues/10522 for details.

        # The course_outline uses this function, and as such will not fully load when run
        # under phantomjs 1.9.8. So, to prevent this test from timing out at course_outline.visit(),
        # force the use of firefox vs the standard a11y test usage of phantomjs 1.9.8.

        # TODO: remove this block once https://openedx.atlassian.net/browse/TE-1047 is resolved.
        if browser == 'phantomjs':
            browser = 'firefox'

        with patch.dict(os.environ, {'SELENIUM_BROWSER': browser}):
            super(StudioSubsectionSettingsA11yTest, self).setUp(is_staff=True)

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

    def populate_course_fixture(self, course_fixture):
        course_fixture.add_advanced_settings({
            "enable_proctored_exams": {"value": "true"}
        })

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection 1').add_children(
                    XBlockFixtureDesc('problem', 'Test Problem 1')
                )
            )
        )

    def test_special_exams_menu_a11y(self):
        """
        Given that I am a staff member
        And I am editing settings on the special exams menu
        Then that menu is accessible
        """
        self.course_outline.visit()
        self.course_outline.open_subsection_settings_dialog()
        self.course_outline.select_advanced_tab()

        # limit the scope of the audit to the special exams tab on the modal dialog
        self.course_outline.a11y_audit.config.set_scope(
            include=['section.edit-settings-timed-examination']
        )
        self.course_outline.a11y_audit.check_for_accessibility_errors()
예제 #3
0
class GatingTest(UniqueCourseTest):
    """
    Test gating feature in LMS.
    """
    STAFF_USERNAME = "******"
    STAFF_EMAIL = "*****@*****.**"

    STUDENT_USERNAME = "******"
    STUDENT_EMAIL = "*****@*****.**"

    def setUp(self):
        super(GatingTest, self).setUp()

        self.logout_page = LogoutPage(self.browser)
        self.course_home_page = CourseHomePage(self.browser, self.course_id)
        self.courseware_page = CoursewarePage(self.browser, self.course_id)
        self.studio_course_outline = StudioCourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        xml = dedent("""
        <problem>
        <p>What is height of eiffel tower without the antenna?.</p>
        <multiplechoiceresponse>
          <choicegroup label="What is height of eiffel tower without the antenna?" type="MultipleChoice">
            <choice correct="false">324 meters<choicehint>Antenna is 24 meters high</choicehint></choice>
            <choice correct="true">300 meters</choice>
            <choice correct="false">224 meters</choice>
            <choice correct="false">400 meters</choice>
          </choicegroup>
        </multiplechoiceresponse>
        </problem>
        """)
        self.problem1 = XBlockFixtureDesc('problem', 'HEIGHT OF EIFFEL TOWER', data=xml)

        # Install a course with sections/problems
        course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name']
        )
        course_fixture.add_advanced_settings({
            "enable_subsection_gating": {"value": "true"}
        })

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection 1').add_children(
                    self.problem1
                ),
                XBlockFixtureDesc('sequential', 'Test Subsection 2').add_children(
                    XBlockFixtureDesc('problem', 'Test Problem 2')
                )
            )
        ).install()

    def _auto_auth(self, username, email, staff):
        """
        Logout and login with given credentials.
        """
        self.logout_page.visit()
        AutoAuthPage(self.browser, username=username, email=email,
                     course_id=self.course_id, staff=staff).visit()

    def _setup_prereq(self):
        """
        Make the first subsection a prerequisite
        """
        # Login as staff
        self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True)

        # Make the first subsection a prerequisite
        self.studio_course_outline.visit()
        self.studio_course_outline.open_subsection_settings_dialog(0)
        self.studio_course_outline.select_advanced_tab(desired_item='gated_content')
        self.studio_course_outline.make_gating_prerequisite()

    def _setup_gated_subsection(self):
        """
        Gate the second 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.select_advanced_tab(desired_item='gated_content')
        self.studio_course_outline.add_prerequisite_to_subsection("80")

    def _fulfill_prerequisite(self):
        """
        Fulfill the prerequisite needed to see gated content
        """
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.wait_for_page().problem_name, 'HEIGHT OF EIFFEL TOWER')
        problem_page.click_choice('choice_1')
        problem_page.click_submit()

    def test_subsection_gating_in_studio(self):
        """
        Given that I am a staff member
        When I visit the course outline page in studio.
        And open the subsection edit dialog
        Then I can view all settings related to Gating
        And update those settings to gate a subsection
        """
        self._setup_prereq()

        # Assert settings are displayed correctly for a prerequisite subsection
        self.studio_course_outline.visit()
        self.studio_course_outline.open_subsection_settings_dialog(0)
        self.studio_course_outline.select_advanced_tab(desired_item='gated_content')
        self.assertTrue(self.studio_course_outline.gating_prerequisite_checkbox_is_visible())
        self.assertTrue(self.studio_course_outline.gating_prerequisite_checkbox_is_checked())
        self.assertFalse(self.studio_course_outline.gating_prerequisites_dropdown_is_visible())
        self.assertFalse(self.studio_course_outline.gating_prerequisite_min_score_is_visible())

        self._setup_gated_subsection()

        # Assert settings are displayed correctly for a gated subsection
        self.studio_course_outline.visit()
        self.studio_course_outline.open_subsection_settings_dialog(1)
        self.studio_course_outline.select_advanced_tab(desired_item='gated_content')
        self.assertTrue(self.studio_course_outline.gating_prerequisite_checkbox_is_visible())
        self.assertTrue(self.studio_course_outline.gating_prerequisites_dropdown_is_visible())
        self.assertTrue(self.studio_course_outline.gating_prerequisite_min_score_is_visible())

    def test_gated_subsection_in_lms_for_student(self):
        """
        Given that I am a student
        When I visit the LMS Courseware
        Then I cannot see a gated subsection
        When I fulfill the gating Prerequisite
        Then I can see the gated subsection
        """
        self._setup_prereq()
        self._setup_gated_subsection()

        self._auto_auth(self.STUDENT_USERNAME, self.STUDENT_EMAIL, False)

        self.course_home_page.visit()
        self.assertEqual(self.course_home_page.outline.num_subsections, 1)

        # 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)

    def test_gated_subsection_in_lms_for_staff(self):
        """
        Given that I am a staff member
        When I visit the LMS Courseware
        Then I can see all gated subsections
        Displayed along with notification banners
        Then if I masquerade as a student
        Then I cannot see a gated subsection
        When I fufill the gating prerequisite
        Then I can see the gated subsection (without a banner)
        """
        self._setup_prereq()
        self._setup_gated_subsection()

        # Fulfill prerequisites for specific student
        self._auto_auth(self.STUDENT_USERNAME, self.STUDENT_EMAIL, False)
        self.courseware_page.visit()
        self._fulfill_prerequisite()

        self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True)

        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)

        # Click on gated section and check for banner
        self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 2')
        self.courseware_page.wait_for_page()
        self.assertTrue(self.courseware_page.has_banner())

        self.course_home_page.visit()
        self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 1')
        self.courseware_page.wait_for_page()

        self.course_home_page.visit()
        self.course_home_page.preview.set_staff_view_mode('Learner')
        self.assertEqual(self.course_home_page.outline.num_subsections, 1)
        self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 1')
        self.courseware_page.wait_for_page()
        self.assertFalse(self.courseware_page.has_banner())

        self.course_home_page.visit()
        self.course_home_page.preview.set_staff_view_mode_specific_student(self.STUDENT_USERNAME)
        self.assertEqual(self.course_home_page.outline.num_subsections, 2)
        self.course_home_page.outline.go_to_section('Test Section 1', 'Test Subsection 2')
        self.courseware_page.wait_for_page()
        self.assertFalse(self.courseware_page.has_banner())
예제 #4
0
class GatingTest(UniqueCourseTest):
    """
    Test gating feature in LMS.
    """
    STAFF_USERNAME = "******"
    STAFF_EMAIL = "*****@*****.**"

    STUDENT_USERNAME = "******"
    STUDENT_EMAIL = "*****@*****.**"

    def setUp(self):
        super(GatingTest, self).setUp()

        self.logout_page = LogoutPage(self.browser)
        self.course_home_page = CourseHomePage(self.browser, self.course_id)
        self.courseware_page = CoursewarePage(self.browser, self.course_id)
        self.studio_course_outline = StudioCourseOutlinePage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        xml = dedent("""
        <problem>
        <p>What is height of eiffel tower without the antenna?.</p>
        <multiplechoiceresponse>
          <choicegroup label="What is height of eiffel tower without the antenna?" type="MultipleChoice">
            <choice correct="false">324 meters<choicehint>Antenna is 24 meters high</choicehint></choice>
            <choice correct="true">300 meters</choice>
            <choice correct="false">224 meters</choice>
            <choice correct="false">400 meters</choice>
          </choicegroup>
        </multiplechoiceresponse>
        </problem>
        """)
        self.problem1 = XBlockFixtureDesc('problem',
                                          'HEIGHT OF EIFFEL TOWER',
                                          data=xml)

        # Install a course with sections/problems
        course_fixture = CourseFixture(self.course_info['org'],
                                       self.course_info['number'],
                                       self.course_info['run'],
                                       self.course_info['display_name'])
        course_fixture.add_advanced_settings(
            {"enable_subsection_gating": {
                "value": "true"
            }})

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
                XBlockFixtureDesc('sequential',
                                  'Test Subsection 1').add_children(
                                      self.problem1),
                XBlockFixtureDesc('sequential',
                                  'Test Subsection 2').add_children(
                                      XBlockFixtureDesc(
                                          'problem',
                                          'Test Problem 2')))).install()

    def _auto_auth(self, username, email, staff):
        """
        Logout and login with given credentials.
        """
        self.logout_page.visit()
        AutoAuthPage(self.browser,
                     username=username,
                     email=email,
                     course_id=self.course_id,
                     staff=staff).visit()

    def _setup_prereq(self):
        """
        Make the first subsection a prerequisite
        """
        # Login as staff
        self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True)

        # Make the first subsection a prerequisite
        self.studio_course_outline.visit()
        self.studio_course_outline.open_subsection_settings_dialog(0)
        self.studio_course_outline.select_advanced_tab(
            desired_item='gated_content')
        self.studio_course_outline.make_gating_prerequisite()

    def _setup_gated_subsection(self):
        """
        Gate the second 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.select_advanced_tab(
            desired_item='gated_content')
        self.studio_course_outline.add_prerequisite_to_subsection("80")

    def _fulfill_prerequisite(self):
        """
        Fulfill the prerequisite needed to see gated content
        """
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.wait_for_page().problem_name,
                         'HEIGHT OF EIFFEL TOWER')
        problem_page.click_choice('choice_1')
        problem_page.click_submit()

    def test_subsection_gating_in_studio(self):
        """
        Given that I am a staff member
        When I visit the course outline page in studio.
        And open the subsection edit dialog
        Then I can view all settings related to Gating
        And update those settings to gate a subsection
        """
        self._setup_prereq()

        # Assert settings are displayed correctly for a prerequisite subsection
        self.studio_course_outline.visit()
        self.studio_course_outline.open_subsection_settings_dialog(0)
        self.studio_course_outline.select_advanced_tab(
            desired_item='gated_content')
        self.assertTrue(self.studio_course_outline.
                        gating_prerequisite_checkbox_is_visible())
        self.assertTrue(self.studio_course_outline.
                        gating_prerequisite_checkbox_is_checked())
        self.assertFalse(self.studio_course_outline.
                         gating_prerequisites_dropdown_is_visible())
        self.assertFalse(self.studio_course_outline.
                         gating_prerequisite_min_score_is_visible())

        self._setup_gated_subsection()

        # Assert settings are displayed correctly for a gated subsection
        self.studio_course_outline.visit()
        self.studio_course_outline.open_subsection_settings_dialog(1)
        self.studio_course_outline.select_advanced_tab(
            desired_item='gated_content')
        self.assertTrue(self.studio_course_outline.
                        gating_prerequisite_checkbox_is_visible())
        self.assertTrue(self.studio_course_outline.
                        gating_prerequisites_dropdown_is_visible())
        self.assertTrue(self.studio_course_outline.
                        gating_prerequisite_min_score_is_visible())

    def test_gated_subsection_in_lms_for_student(self):
        """
        Given that I am a student
        When I visit the LMS Courseware
        Then I can see a gated subsection
            The gated subsection should have a lock icon
            and be in the format: "<Subsection Title> (Prerequisite Required)"
        When I fulfill the gating Prerequisite
        Then I can see the gated subsection
            Now the gated subsection should have an unlock icon
            and screen readers should read the section as: "<Subsection Title> Unlocked"
        """
        self._setup_prereq()
        self._setup_gated_subsection()

        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)

        # 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)

    def test_gated_subsection_in_lms_for_staff(self):
        """
        Given that I am a staff member
        When I visit the LMS Courseware
        Then I can see all gated subsections
        Displayed along with notification banners
        Then if I masquerade as a student
        Then I can see a gated subsection
            The gated subsection should have a lock icon
            and be in the format: "<Subsection Title> (Prerequisite Required)"
        """
        self._setup_prereq()
        self._setup_gated_subsection()

        self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True)

        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)

        # Click on gated section and check for banner
        self.course_home_page.outline.go_to_section('Test Section 1',
                                                    'Test Subsection 2')
        self.courseware_page.wait_for_page()
        self.assertTrue(self.courseware_page.has_banner())

        self.course_home_page.visit()
        self.course_home_page.outline.go_to_section('Test Section 1',
                                                    'Test Subsection 1')
        self.courseware_page.wait_for_page()

        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.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())
예제 #5
0
class ProctoredExamTest(UniqueCourseTest):
    """
    Test courseware.
    """
    USERNAME = "******"
    EMAIL = "*****@*****.**"

    def setUp(self):
        super(ProctoredExamTest, self).setUp()

        self.courseware_page = CoursewarePage(self.browser, self.course_id)

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

        # Install a course with sections/problems, tabs, updates, and handouts
        course_fix = CourseFixture(self.course_info['org'],
                                   self.course_info['number'],
                                   self.course_info['run'],
                                   self.course_info['display_name'])
        course_fix.add_advanced_settings(
            {"enable_proctored_exams": {
                "value": "true"
            }})

        course_fix.add_children(
            XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
                XBlockFixtureDesc('sequential',
                                  'Test Subsection 1').add_children(
                                      XBlockFixtureDesc(
                                          'problem',
                                          'Test Problem 1')))).install()

        self.track_selection_page = TrackSelectionPage(self.browser,
                                                       self.course_id)
        self.payment_and_verification_flow = PaymentAndVerificationFlow(
            self.browser, self.course_id)
        self.immediate_verification_page = PaymentAndVerificationFlow(
            self.browser, self.course_id, entry_point='verify-now')
        self.upgrade_page = PaymentAndVerificationFlow(self.browser,
                                                       self.course_id,
                                                       entry_point='upgrade')
        self.fake_payment_page = FakePaymentPage(self.browser, self.course_id)
        self.dashboard_page = DashboardPage(self.browser)
        self.problem_page = ProblemPage(self.browser)

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

        # Auto-auth register for the course.
        self._auto_auth(self.USERNAME, self.EMAIL, False)

    def _auto_auth(self, username, email, staff):
        """
        Logout and login with given credentials.
        """
        AutoAuthPage(self.browser,
                     username=username,
                     email=email,
                     course_id=self.course_id,
                     staff=staff).visit()

    def _login_as_a_verified_user(self):
        """
        login as a verififed user
        """

        self._auto_auth(self.USERNAME, self.EMAIL, False)

        # the track selection page cannot be visited. see the other tests to see if any prereq is there.
        # Navigate to the track selection page
        self.track_selection_page.visit()

        # Enter the payment and verification flow by choosing to enroll as verified
        self.track_selection_page.enroll('verified')

        # Proceed to the fake payment page
        self.payment_and_verification_flow.proceed_to_payment()

        # Submit payment
        self.fake_payment_page.submit_payment()

    def test_can_create_proctored_exam_in_studio(self):
        """
        Given that I am a staff member
        When I visit the course outline page in studio.
        And open the subsection edit dialog
        Then I can view all settings related to Proctored and timed exams
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()

        self.course_outline.open_subsection_settings_dialog()
        self.assertTrue(self.course_outline.proctoring_items_are_displayed())

    def test_proctored_exam_flow(self):
        """
        Given that I am a staff member on the exam settings section
        select advanced settings tab
        When I Make the exam proctored.
        And I login as a verified student.
        And visit the courseware as a verified student.
        Then I can see an option to take the exam as a proctored exam.
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()
        self.course_outline.open_subsection_settings_dialog()

        self.course_outline.select_advanced_tab()
        self.course_outline.make_exam_proctored()

        LogoutPage(self.browser).visit()
        self._login_as_a_verified_user()

        self.courseware_page.visit()
        self.assertTrue(self.courseware_page.can_start_proctored_exam)

    def _setup_and_take_timed_exam(self, hide_after_due=False):
        """
        Helper to perform the common action "set up a timed exam as staff,
        then take it as student"
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()
        self.course_outline.open_subsection_settings_dialog()

        self.course_outline.select_advanced_tab()
        self.course_outline.make_exam_timed(hide_after_due=hide_after_due)

        LogoutPage(self.browser).visit()
        self._login_as_a_verified_user()
        self.courseware_page.visit()

        self.courseware_page.start_timed_exam()
        self.assertTrue(self.courseware_page.is_timer_bar_present)

        self.courseware_page.stop_timed_exam()
        self.assertTrue(self.courseware_page.has_submitted_exam_message())

        LogoutPage(self.browser).visit()

    @ddt.data(True, False)
    def test_timed_exam_flow(self, hide_after_due):
        """
        Given that I am a staff member on the exam settings section
        select advanced settings tab
        When I Make the exam timed.
        And I login as a verified student.
        And visit the courseware as a verified student.
        And I start the timed exam
        Then I am taken to the exam with a timer bar showing
        When I finish the exam
        Then I see the exam submitted dialog in place of the exam
        When I log back into studio as a staff member
        And change the problem's due date to be in the past
        And log back in as the original verified student
        Then I see the exam or message in accordance with the hide_after_due setting
        """
        self._setup_and_take_timed_exam(hide_after_due)

        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()
        last_week = (datetime.today() - timedelta(days=7)).strftime("%m/%d/%Y")
        self.course_outline.change_problem_due_date(last_week)

        LogoutPage(self.browser).visit()
        self._auto_auth(self.USERNAME, self.EMAIL, False)
        self.courseware_page.visit()
        self.assertEqual(self.courseware_page.has_submitted_exam_message(),
                         hide_after_due)

    def test_masquerade_visibility_override(self):
        """
        Given that a timed exam problem exists in the course
        And a student has taken that exam
        And that exam is hidden to the student
        And I am a staff user masquerading as the student
        Then I should be able to see the exam content
        """
        self._setup_and_take_timed_exam()

        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.courseware_page.visit()
        staff_page = StaffPage(self.browser, self.course_id)
        self.assertEqual(staff_page.staff_view_mode, 'Staff')

        staff_page.set_staff_view_mode_specific_student(self.USERNAME)
        self.assertFalse(self.courseware_page.has_submitted_exam_message())

    def test_field_visiblity_with_all_exam_types(self):
        """
        Given that I am a staff member
        And I have visited the course outline page in studio.
        And the subsection edit dialog is open
        select advanced settings tab
        For each of None, Timed, Proctored, and Practice exam types
        The time allotted and review rules fields have proper visibility
        None: False, False
        Timed: True, False
        Proctored: True, True
        Practice: True, False
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()

        self.course_outline.open_subsection_settings_dialog()
        self.course_outline.select_advanced_tab()

        self.course_outline.select_none_exam()
        self.assertFalse(self.course_outline.time_allotted_field_visible())
        self.assertFalse(self.course_outline.exam_review_rules_field_visible())

        self.course_outline.select_timed_exam()
        self.assertTrue(self.course_outline.time_allotted_field_visible())
        self.assertFalse(self.course_outline.exam_review_rules_field_visible())

        self.course_outline.select_proctored_exam()
        self.assertTrue(self.course_outline.time_allotted_field_visible())
        self.assertTrue(self.course_outline.exam_review_rules_field_visible())

        self.course_outline.select_practice_exam()
        self.assertTrue(self.course_outline.time_allotted_field_visible())
        self.assertFalse(self.course_outline.exam_review_rules_field_visible())
class ProctoredExamTest(UniqueCourseTest):
    """
    Test courseware.
    """
    USERNAME = "******"
    EMAIL = "*****@*****.**"

    def setUp(self):
        super(ProctoredExamTest, self).setUp()

        self.courseware_page = CoursewarePage(self.browser, self.course_id)

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

        # Install a course with sections/problems, tabs, updates, and handouts
        course_fix = CourseFixture(
            self.course_info['org'], self.course_info['number'],
            self.course_info['run'], self.course_info['display_name']
        )
        course_fix.add_advanced_settings({
            "enable_proctored_exams": {"value": "true"}
        })

        course_fix.add_children(
            XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection 1').add_children(
                    XBlockFixtureDesc('problem', 'Test Problem 1')
                )
            )
        ).install()

        self.track_selection_page = TrackSelectionPage(self.browser, self.course_id)
        self.payment_and_verification_flow = PaymentAndVerificationFlow(self.browser, self.course_id)
        self.immediate_verification_page = PaymentAndVerificationFlow(
            self.browser, self.course_id, entry_point='verify-now'
        )
        self.upgrade_page = PaymentAndVerificationFlow(self.browser, self.course_id, entry_point='upgrade')
        self.fake_payment_page = FakePaymentPage(self.browser, self.course_id)
        self.dashboard_page = DashboardPage(self.browser)
        self.problem_page = ProblemPage(self.browser)

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

        # Auto-auth register for the course.
        self._auto_auth(self.USERNAME, self.EMAIL, False)

    def _auto_auth(self, username, email, staff):
        """
        Logout and login with given credentials.
        """
        AutoAuthPage(self.browser, username=username, email=email,
                     course_id=self.course_id, staff=staff).visit()

    def _login_as_a_verified_user(self):
        """
        login as a verififed user
        """

        self._auto_auth(self.USERNAME, self.EMAIL, False)

        # the track selection page cannot be visited. see the other tests to see if any prereq is there.
        # Navigate to the track selection page
        self.track_selection_page.visit()

        # Enter the payment and verification flow by choosing to enroll as verified
        self.track_selection_page.enroll('verified')

        # Proceed to the fake payment page
        self.payment_and_verification_flow.proceed_to_payment()

        # Submit payment
        self.fake_payment_page.submit_payment()

    def test_can_create_proctored_exam_in_studio(self):
        """
        Given that I am a staff member
        When I visit the course outline page in studio.
        And open the subsection edit dialog
        Then I can view all settings related to Proctored and timed exams
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()

        self.course_outline.open_subsection_settings_dialog()
        self.assertTrue(self.course_outline.proctoring_items_are_displayed())

    def test_proctored_exam_flow(self):
        """
        Given that I am a staff member on the exam settings section
        select advanced settings tab
        When I Make the exam proctored.
        And I login as a verified student.
        And visit the courseware as a verified student.
        Then I can see an option to take the exam as a proctored exam.
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()
        self.course_outline.open_subsection_settings_dialog()

        self.course_outline.select_advanced_tab()
        self.course_outline.make_exam_proctored()

        LogoutPage(self.browser).visit()
        self._login_as_a_verified_user()

        self.courseware_page.visit()
        self.assertTrue(self.courseware_page.can_start_proctored_exam)

    def _setup_and_take_timed_exam(self, hide_after_due=False):
        """
        Helper to perform the common action "set up a timed exam as staff,
        then take it as student"
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()
        self.course_outline.open_subsection_settings_dialog()

        self.course_outline.select_advanced_tab()
        self.course_outline.make_exam_timed(hide_after_due=hide_after_due)

        LogoutPage(self.browser).visit()
        self._login_as_a_verified_user()
        self.courseware_page.visit()

        self.courseware_page.start_timed_exam()
        self.assertTrue(self.courseware_page.is_timer_bar_present)

        self.courseware_page.stop_timed_exam()
        self.assertTrue(self.courseware_page.has_submitted_exam_message())

        LogoutPage(self.browser).visit()

    @ddt.data(True, False)
    def test_timed_exam_flow(self, hide_after_due):
        """
        Given that I am a staff member on the exam settings section
        select advanced settings tab
        When I Make the exam timed.
        And I login as a verified student.
        And visit the courseware as a verified student.
        And I start the timed exam
        Then I am taken to the exam with a timer bar showing
        When I finish the exam
        Then I see the exam submitted dialog in place of the exam
        When I log back into studio as a staff member
        And change the problem's due date to be in the past
        And log back in as the original verified student
        Then I see the exam or message in accordance with the hide_after_due setting
        """
        self._setup_and_take_timed_exam(hide_after_due)

        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()
        last_week = (datetime.today() - timedelta(days=7)).strftime("%m/%d/%Y")
        self.course_outline.change_problem_due_date(last_week)

        LogoutPage(self.browser).visit()
        self._auto_auth(self.USERNAME, self.EMAIL, False)
        self.courseware_page.visit()
        self.assertEqual(self.courseware_page.has_submitted_exam_message(), hide_after_due)

    def test_masquerade_visibility_override(self):
        """
        Given that a timed exam problem exists in the course
        And a student has taken that exam
        And that exam is hidden to the student
        And I am a staff user masquerading as the student
        Then I should be able to see the exam content
        """
        self._setup_and_take_timed_exam()

        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.courseware_page.visit()
        staff_page = StaffPage(self.browser, self.course_id)
        self.assertEqual(staff_page.staff_view_mode, 'Staff')

        staff_page.set_staff_view_mode_specific_student(self.USERNAME)
        self.assertFalse(self.courseware_page.has_submitted_exam_message())

    def test_field_visiblity_with_all_exam_types(self):
        """
        Given that I am a staff member
        And I have visited the course outline page in studio.
        And the subsection edit dialog is open
        select advanced settings tab
        For each of None, Timed, Proctored, and Practice exam types
        The time allotted and review rules fields have proper visibility
        None: False, False
        Timed: True, False
        Proctored: True, True
        Practice: True, False
        """
        LogoutPage(self.browser).visit()
        self._auto_auth("STAFF_TESTER", "*****@*****.**", True)
        self.course_outline.visit()

        self.course_outline.open_subsection_settings_dialog()
        self.course_outline.select_advanced_tab()

        self.course_outline.select_none_exam()
        self.assertFalse(self.course_outline.time_allotted_field_visible())
        self.assertFalse(self.course_outline.exam_review_rules_field_visible())

        self.course_outline.select_timed_exam()
        self.assertTrue(self.course_outline.time_allotted_field_visible())
        self.assertFalse(self.course_outline.exam_review_rules_field_visible())

        self.course_outline.select_proctored_exam()
        self.assertTrue(self.course_outline.time_allotted_field_visible())
        self.assertTrue(self.course_outline.exam_review_rules_field_visible())

        self.course_outline.select_practice_exam()
        self.assertTrue(self.course_outline.time_allotted_field_visible())
        self.assertFalse(self.course_outline.exam_review_rules_field_visible())