def test_hinted_login(self): """ Test the login page when coming from course URL that specified which third party provider to use """ # Create a user account and link it to third party auth with the dummy provider: AutoAuthPage(self.browser, course_id=self.course_id).visit() self._link_dummy_account() try: LogoutPage(self.browser).visit() # When not logged in, try to load a course URL that includes the provider hint ?tpa_hint=... course_page = CoursewarePage(self.browser, self.course_id) self.browser.get(course_page.url + '?tpa_hint=oa2-dummy') # We should now be redirected to the login page self.login_page.wait_for_page() self.assertIn( "Would you like to sign in using your Dummy credentials?", self.login_page.hinted_login_prompt ) # Baseline screen-shots are different for chrome and firefox. #self.assertScreenshot('#hinted-login-form', 'hinted-login-{}'.format(self.browser.name), .25) #The line above is commented out temporarily see SOL-1937 self.login_page.click_third_party_dummy_provider() # We should now be redirected to the course page course_page.wait_for_page() finally: self._unlink_dummy_account()
def test_course_updated_with_entrance_exam(self): """ Given that I visit an empty course before import I should not see a section named 'Section' or 'Entrance Exam' When I visit the import page And I upload a course that has an entrance exam section named 'Entrance Exam' And I visit the course outline page again The section named 'Entrance Exam' should now be available. And when I switch the view mode to student view and Visit CourseWare Then I see one section in the sidebar that is 'Entrance Exam' """ self.landing_page.visit() # Should not exist yet. self.assertRaises(IndexError, self.landing_page.section, "Section") self.assertRaises(IndexError, self.landing_page.section, "Entrance Exam") self.import_page.visit() self.import_page.upload_tarball(self.tarball_name) self.import_page.wait_for_upload() self.landing_page.visit() # There should be two sections. 'Entrance Exam' and 'Section' on the landing page. self.landing_page.section("Entrance Exam") self.landing_page.section("Section") self.landing_page.view_live() courseware = CoursewarePage(self.browser, self.course_id) courseware.wait_for_page() StaffPage(self.browser, self.course_id).set_staff_view_mode('Student') self.assertEqual(courseware.num_sections, 1) self.assertIn( "To access course materials, you must score", courseware.entrance_exam_message_selector.text[0] )
class StaffViewTest(UniqueCourseTest): """ Tests that verify the staff view. """ USERNAME = "******" EMAIL = "*****@*****.**" def setUp(self): super(StaffViewTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with sections/problems, tabs, updates, and handouts self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.populate_course_fixture(self.course_fixture) # pylint: disable=no-member self.course_fixture.install() # Auto-auth register for the course. # Do this as global staff so that you will see the Staff View AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=True).visit() def _goto_staff_page(self): """ Open staff page with assertion """ self.courseware_page.visit() staff_page = StaffPage(self.browser, self.course_id) self.assertEqual(staff_page.staff_view_mode, 'Staff') return staff_page
def test_course_rerun(self): """ Scenario: Courses can be rerun Given I have a course with a section, subsesction, vertical, and html component with content 'Test Content' When I visit the course rerun page And I type 'test_rerun' in the course run field And I click Create Rerun And I visit the course listing page And I wait for all courses to finish processing And I click on the course with run 'test_rerun' Then I see a rerun notification on the course outline page And when I click 'Dismiss' on the notification Then I do not see a rerun notification And when I expand the subsection and click on the unit And I click 'View Live Version' Then I see one html component with the content 'Test Content' """ course_info = (self.course_info['org'], self.course_info['number'], self.course_info['run']) updated_course_info = course_info[0] + "+" + course_info[1] + "+" + course_info[2] self.dashboard_page.visit() self.dashboard_page.scroll_to_course(course_info[1]) self.dashboard_page.create_rerun(updated_course_info) rerun_page = CourseRerunPage(self.browser, *course_info) rerun_page.wait_for_page() course_run = 'test_rerun_' + str(random.randrange(1000000, 9999999)) rerun_page.course_run = course_run rerun_page.create_rerun() def finished_processing(): self.dashboard_page.visit() return not self.dashboard_page.has_processing_courses EmptyPromise(finished_processing, "Rerun finished processing", try_interval=5, timeout=60).fulfill() assert_in(course_run, self.dashboard_page.course_runs) self.dashboard_page.click_course_run(course_run) outline_page = CourseOutlinePage(self.browser, *course_info) outline_page.wait_for_page() self.assertTrue(outline_page.has_rerun_notification) outline_page.dismiss_rerun_notification() EmptyPromise(lambda: not outline_page.has_rerun_notification, "Rerun notification dismissed").fulfill() subsection = outline_page.section(self.SECTION_NAME).subsection(self.SUBSECITON_NAME) subsection.expand_subsection() unit_page = subsection.unit(self.UNIT_NAME).go_to() unit_page.view_published_version() courseware = CoursewarePage(self.browser, self.course_id) courseware.wait_for_page() self.assertEqual(courseware.num_xblock_components, 1) self.assertEqual(courseware.xblock_component_html_content(), self.COMPONENT_CONTENT)
def setUp(self): super(CoursewareTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_nav = CourseNavPage(self.browser) 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 self.course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section 1').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 1').add_children( XBlockFixtureDesc('problem', 'Test Problem 1') ) ), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 2').add_children( XBlockFixtureDesc('problem', 'Test Problem 2') ) ) ).install() # Auto-auth register for the course. self._auto_auth(self.USERNAME, self.EMAIL, False)
def setUp(self): super(ProblemStateOnNavigationTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with section, tabs and multiple choice problems. course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section 1').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 1,1').add_children( self.create_multiple_choice_problem(self.problem1_name), self.create_multiple_choice_problem(self.problem2_name), ), ), ).install() # Auto-auth register for the course. AutoAuthPage( self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False ).visit() self.courseware_page.visit() self.problem_page = ProblemPage(self.browser)
def setUp(self): """ Initialize pages and install a course fixture. """ super(TooltipTest, self).setUp() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.tab_nav = TabNavPage(self.browser) course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('static_tab', 'Test Static Tab'), XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('problem', 'Test Problem 1', data=load_data_str('multiple_choice.xml')), XBlockFixtureDesc('problem', 'Test Problem 2', data=load_data_str('formula_problem.xml')), XBlockFixtureDesc('html', 'Test HTML'), ) ) ).install() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Auto-auth register for the course AutoAuthPage(self.browser, course_id=self.course_id).visit()
def setUp(self): """ Initialization of pages and course fixture for video tests """ super(VideoBaseTest, self).setUp() self.longMessage = True self.video = VideoPage(self.browser) self.tab_nav = TabNavPage(self.browser) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_info_page = CourseInfoPage(self.browser, self.course_id) self.auth_page = AutoAuthPage(self.browser, course_id=self.course_id) self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.metadata = None self.assets = [] self.contents_of_verticals = None self.youtube_configuration = {} self.user_info = {} # reset youtube stub server self.addCleanup(YouTubeStubConfig.reset)
def setUp(self): super(CertificateProgressPageTest, self).setUp() # set same course number as we have in fixture json self.course_info['number'] = "3355358979513794782079645765720179311111" test_certificate_config = { 'id': 1, 'name': 'Certificate name', 'description': 'Certificate description', 'course_title': 'Course title override', 'signatories': [], 'version': 1, 'is_active': True } course_settings = {'certificates': test_certificate_config} self.course_fixture = CourseFixture( self.course_info["org"], self.course_info["number"], self.course_info["run"], self.course_info["display_name"], settings=course_settings ) self.course_fixture.add_advanced_settings({ "cert_html_view_enabled": {"value": "true"}, "certificates_show_before_end": {"value": "true"} }) self.course_fixture.add_update( CourseUpdateDesc(date='January 29, 2014', content='Test course update1') ) self.course_fixture.add_children( XBlockFixtureDesc('static_tab', 'Test Static Tab'), XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection', grader_type='Final Exam').add_children( XBlockFixtureDesc('problem', 'Test Problem 1', data=load_data_str('multiple_choice.xml')), XBlockFixtureDesc('html', 'Test HTML'), ) ), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 2', grader_type='Midterm Exam').add_children( XBlockFixtureDesc('problem', 'Test Problem 2', data=load_data_str('formula_problem.xml')), ) ) ) self.course_fixture.install() self.user_id = "99" # we have created a user with this id in fixture self.cert_fixture = CertificateConfigFixture(self.course_id, test_certificate_config) self.course_info_page = CourseInfoPage(self.browser, self.course_id) self.progress_page = ProgressPage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_home_page = CourseHomePage(self.browser, self.course_id) self.tab_nav = TabNavPage(self.browser)
def setUp(self): super(ConditionalTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) AutoAuthPage( self.browser, course_id=self.course_id, staff=False ).visit()
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"}, 'enable_proctored_exams': {"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') ), XBlockFixtureDesc('sequential', 'Test Subsection 3').add_children( XBlockFixtureDesc('problem', 'Test Problem 3') ), ) ).install()
def setUp(self): # pylint: disable=arguments-differ super(VideoLicenseTest, self).setUp() self.lms_courseware = CoursewarePage( self.browser, self.course_id, ) self.studio_course_outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] )
def setUp(self): super(CoursewareMultipleVerticalsTest, 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_children( XBlockFixtureDesc('chapter', 'Test Section 1').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 1,1').add_children( XBlockFixtureDesc('problem', 'Test Problem 1', data='<problem>problem 1 dummy body</problem>'), XBlockFixtureDesc('html', 'html 1', data="<html>html 1 dummy body</html>"), XBlockFixtureDesc('problem', 'Test Problem 2', data="<problem>problem 2 dummy body</problem>"), XBlockFixtureDesc('html', 'html 2', data="<html>html 2 dummy body</html>"), ), XBlockFixtureDesc('sequential', 'Test Subsection 1,2').add_children( XBlockFixtureDesc('problem', 'Test Problem 3', data='<problem>problem 3 dummy body</problem>'), ), XBlockFixtureDesc( 'sequential', 'Test HIDDEN Subsection', metadata={'visible_to_staff_only': True} ).add_children( XBlockFixtureDesc('problem', 'Test HIDDEN Problem', data='<problem>hidden problem</problem>'), ), ), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc('sequential', 'Test Subsection 2,1').add_children( XBlockFixtureDesc('problem', 'Test Problem 4', data='<problem>problem 4 dummy body</problem>'), ), ), XBlockFixtureDesc('chapter', 'Test HIDDEN Section', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('sequential', 'Test HIDDEN Subsection'), ), ).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit() self.courseware_page.visit() self.course_nav = CourseNavPage(self.browser)
def setUp(self): """ Set up library, course and library content XBlock """ super(LibraryContentTestBase, 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'] ) self.library_fixture = LibraryFixture('test_org', self.unique_id, 'Test Library {}'.format(self.unique_id)) self.populate_library_fixture(self.library_fixture) self.library_fixture.install() self.library_info = self.library_fixture.library_info self.library_key = self.library_fixture.library_key # Install a course with library content xblock self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) library_content_metadata = { 'source_library_id': unicode(self.library_key), 'mode': 'random', 'max_count': 1, 'has_score': False } self.lib_block = XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata) self.course_fixture.add_children( XBlockFixtureDesc('chapter', SECTION_NAME).add_children( XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children( XBlockFixtureDesc('vertical', UNIT_NAME).add_children( self.lib_block ) ) ) ) self.course_fixture.install()
def test_entrance_exam_section_2(self): """ Scenario: Any course that is enabled for an entrance exam, should have entrance exam chapter at course page. Given that I am on the course page When I view the course that has an entrance exam Then there should be an "Entrance Exam" chapter.' """ courseware_page = CoursewarePage(self.browser, self.course_id) entrance_exam_link_selector = '.accordion .course-navigation .chapter .group-heading' # visit course page and make sure there is not entrance exam chapter. courseware_page.visit() courseware_page.wait_for_page() self.assertFalse(element_has_text( page=courseware_page, css_selector=entrance_exam_link_selector, text='Entrance Exam' )) # Logout and login as a staff. LogoutPage(self.browser).visit() AutoAuthPage(self.browser, course_id=self.course_id, staff=True).visit() # visit course settings page and set/enabled entrance exam for that course. self.settings_page.visit() self.settings_page.require_entrance_exam() self.settings_page.save_changes() # Logout and login as a student. LogoutPage(self.browser).visit() AutoAuthPage(self.browser, course_id=self.course_id, staff=False).visit() # visit course info page and make sure there is an "Entrance Exam" section. courseware_page.visit() courseware_page.wait_for_page() self.assertTrue(element_has_text( page=courseware_page, css_selector=entrance_exam_link_selector, text='Entrance Exam' ))
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 setUp(self): """ Set up library, course and library content XBlock """ super(LibraryContentTestBase, 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"] ) self.library_fixture = LibraryFixture("test_org", self.unique_id, "Test Library {}".format(self.unique_id)) self.populate_library_fixture(self.library_fixture) self.library_fixture.install() self.library_info = self.library_fixture.library_info self.library_key = self.library_fixture.library_key # Install a course with library content xblock self.course_fixture = CourseFixture( self.course_info["org"], self.course_info["number"], self.course_info["run"], self.course_info["display_name"], ) library_content_metadata = { "source_library_id": unicode(self.library_key), "mode": "random", "max_count": 1, "has_score": False, } self.lib_block = XBlockFixtureDesc("library_content", "Library Content", metadata=library_content_metadata) self.course_fixture.add_children( XBlockFixtureDesc("chapter", SECTION_NAME).add_children( XBlockFixtureDesc("sequential", SUBSECTION_NAME).add_children( XBlockFixtureDesc("vertical", UNIT_NAME).add_children(self.lib_block) ) ) ) self.course_fixture.install()
def setUp(self): super(StaffViewTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with sections/problems, tabs, updates, and handouts self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.populate_course_fixture(self.course_fixture) # pylint: disable=no-member self.course_fixture.install() # Auto-auth register for the course. # Do this as global staff so that you will see the Staff View AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=True).visit()
def setUp(self): # pylint: disable=arguments-differ super(ContentLicenseTest, self).setUp() self.outline_page = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.settings_page = SettingsPage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.lms_courseware = CoursewarePage( self.browser, self.course_id, ) self.settings_page.visit()
def setUp(self): super(BookmarksTestMixin, self).setUp() self.studio_course_outline_page = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_home_page = CourseHomePage(self.browser, self.course_id) self.bookmarks_page = BookmarksPage(self.browser, self.course_id) # Get session to be used for bookmarking units self.session = requests.Session() params = {'username': self.USERNAME, 'email': self.EMAIL, 'course_id': self.course_id} response = self.session.get(BASE_URL + "/auto_auth", params=params) self.assertTrue(response.ok, "Failed to get session")
def setUp(self): super(AnnotatableProblemTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with two annotations and two annotations problems. course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.annotation_count = 2 course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Annotation Vertical').add_children( XBlockFixtureDesc('annotatable', 'Test Annotation Module', data=self.DATA_TEMPLATE.format("\n".join( self.ANNOTATION_TEMPLATE.format(i) for i in xrange(self.annotation_count) ))), XBlockFixtureDesc('problem', 'Test Annotation Problem 0', data=self.PROBLEM_TEMPLATE.format(number=0, options="\n".join( self.OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, 0)) for k in xrange(self.annotation_count) ))), XBlockFixtureDesc('problem', 'Test Annotation Problem 1', data=self.PROBLEM_TEMPLATE.format(number=1, options="\n".join( self.OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, 1)) for k in xrange(self.annotation_count) ))) ) ) ) ).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit()
def setUp(self): super(CrowdsourcehinterProblemTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # 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'] ) problem_data = dedent(''' <problem> <p>A text input problem accepts a line of text from the student, and evaluates the input for correctness based on an expected answer.</p> <p>The answer is correct if it matches every character of the expected answer. This can be a problem with international spelling, dates, or anything where the format of the answer is not clear.</p> <p>Which US state has Lansing as its capital?</p> <stringresponse answer="Michigan" type="ci" > <textline label="Which US state has Lansing as its capital?" size="20"/> </stringresponse> <solution> <div class="detailed-solution"> <p>Explanation</p> <p>Lansing is the capital of Michigan, although it is not Michigan's largest city, or even the seat of the county in which it resides.</p> </div> </solution> </problem> ''') children = XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('problem', 'text input problem', data=problem_data), XBlockFixtureDesc('crowdsourcehinter', 'test crowdsourcehinter') ) ) ) course_fix.add_children(children).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit()
def setUp(self): super(VisibleToStaffOnlyTest, self).setUp() course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Subsection With Locked Unit').add_children( XBlockFixtureDesc('vertical', 'Locked Unit', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('html', 'Html Child in locked unit', data="<html>Visible only to staff</html>"), ), XBlockFixtureDesc('vertical', 'Unlocked Unit').add_children( XBlockFixtureDesc('html', 'Html Child in unlocked unit', data="<html>Visible only to all</html>"), ) ), XBlockFixtureDesc('sequential', 'Unlocked Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('html', 'Html Child in visible unit', data="<html>Visible to all</html>"), ) ), XBlockFixtureDesc('sequential', 'Locked Subsection', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'html', 'Html Child in locked subsection', data="<html>Visible only to staff</html>" ) ) ) ) ).install() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id)
class VisibleToStaffOnlyTest(UniqueCourseTest): """ Tests that content with visible_to_staff_only set to True cannot be viewed by students. """ def setUp(self): super(VisibleToStaffOnlyTest, self).setUp() course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Subsection With Locked Unit').add_children( XBlockFixtureDesc('vertical', 'Locked Unit', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('html', 'Html Child in locked unit', data="<html>Visible only to staff</html>"), ), XBlockFixtureDesc('vertical', 'Unlocked Unit').add_children( XBlockFixtureDesc('html', 'Html Child in unlocked unit', data="<html>Visible only to all</html>"), ) ), XBlockFixtureDesc('sequential', 'Unlocked Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('html', 'Html Child in visible unit', data="<html>Visible to all</html>"), ) ), XBlockFixtureDesc('sequential', 'Locked Subsection', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'html', 'Html Child in locked subsection', data="<html>Visible only to staff</html>" ) ) ) ) ).install() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id) def test_visible_to_student(self): """ Scenario: Content marked 'visible_to_staff_only' is not visible for students in the course Given some of the course content has been marked 'visible_to_staff_only' And I am logged on with an authorized student account Then I can only see content without 'visible_to_staff_only' set to True """ AutoAuthPage(self.browser, username="******", email="*****@*****.**", course_id=self.course_id, staff=False).visit() self.course_home_page.visit() self.assertEqual(2, len(self.course_home_page.outline.sections['Test Section'])) self.course_home_page.outline.go_to_section("Test Section", "Subsection With Locked Unit") self.courseware_page.wait_for_page() self.assertEqual([u'Unlocked Unit'], self.courseware_page.nav.sequence_items) self.course_home_page.visit() self.course_home_page.outline.go_to_section("Test Section", "Unlocked Subsection") self.courseware_page.wait_for_page() self.assertEqual([u'Test Unit'], self.courseware_page.nav.sequence_items)
def setUp(self): super(CertificateProgressPageTest, self).setUp() # set same course number as we have in fixture json self.course_info['number'] = "3355358979513794782079645765720179311111" test_certificate_config = { 'id': 1, 'name': 'Certificate name', 'description': 'Certificate description', 'course_title': 'Course title override', 'signatories': [], 'version': 1, 'is_active': True } course_settings = {'certificates': test_certificate_config} self.course_fixture = CourseFixture(self.course_info["org"], self.course_info["number"], self.course_info["run"], self.course_info["display_name"], settings=course_settings) self.course_fixture.add_advanced_settings( {"cert_html_view_enabled": { "value": "true" }}) self.course_fixture.add_update( CourseUpdateDesc(date='January 29, 2014', content='Test course update1')) self.course_fixture.add_children( XBlockFixtureDesc('static_tab', 'Test Static Tab'), XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection', grader_type='Final Exam').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 1', data=load_data_str('multiple_choice.xml')), XBlockFixtureDesc('html', 'Test HTML'), )), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection 2', grader_type='Midterm Exam').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 2', data=load_data_str('formula_problem.xml')), ))) self.course_fixture.install() self.user_id = "99" # we have created a user with this id in fixture self.cert_fixture = CertificateConfigFixture(self.course_id, test_certificate_config) self.course_info_page = CourseInfoPage(self.browser, self.course_id) self.progress_page = ProgressPage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_home_page = CourseHomePage(self.browser, self.course_id) self.tab_nav = TabNavPage(self.browser)
class LibraryContentTestBase(UniqueCourseTest): """ Base class for library content block tests """ USERNAME = "******" EMAIL = "*****@*****.**" STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" def populate_library_fixture(self, library_fixture): """ To be overwritten by subclassed tests. Used to install a library to run tests on. """ def setUp(self): """ Set up library, course and library content XBlock """ super(LibraryContentTestBase, self).setUp() 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'] ) self.library_fixture = LibraryFixture('test_org', self.unique_id, 'Test Library {}'.format(self.unique_id)) self.populate_library_fixture(self.library_fixture) self.library_fixture.install() self.library_info = self.library_fixture.library_info self.library_key = self.library_fixture.library_key # Install a course with library content xblock self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) library_content_metadata = { 'source_library_id': unicode(self.library_key), 'mode': 'random', 'max_count': 1, } self.lib_block = XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata) self.course_fixture.add_children( XBlockFixtureDesc('chapter', SECTION_NAME).add_children( XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children( XBlockFixtureDesc('vertical', UNIT_NAME).add_children( self.lib_block ) ) ) ) self.course_fixture.install() def _change_library_content_settings(self, count=1, capa_type=None): """ Performs library block refresh in Studio, configuring it to show {count} children """ unit_page = self._go_to_unit_page(True) library_container_block = StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(unit_page.xblocks[1]) library_container_block.edit() editor = StudioLibraryContentEditor(self.browser, library_container_block.locator) editor.count = count if capa_type is not None: editor.capa_type = capa_type editor.save() self._go_to_unit_page(change_login=False) unit_page.wait_for_page() unit_page.publish_action.click() unit_page.wait_for_ajax() self.assertIn("Published and Live", unit_page.publish_title) @property def library_xblocks_texts(self): """ Gets texts of all xblocks in library """ return frozenset(child.data for child in self.library_fixture.children) def _go_to_unit_page(self, change_login=True): """ Open unit page in Studio """ if change_login: LogoutPage(self.browser).visit() self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() subsection = self.studio_course_outline.section(SECTION_NAME).subsection(SUBSECTION_NAME) return subsection.expand_subsection().unit(UNIT_NAME).go_to() def _goto_library_block_page(self, block_id=None): """ Open library page in LMS """ self.courseware_page.visit() paragraphs = self.courseware_page.q(css='.course-content p').results if not paragraphs: course_home_page = CourseHomePage(self.browser, self.course_id) course_home_page.visit() course_home_page.outline.go_to_section_by_index(0, 0) block_id = block_id if block_id is not None else self.lib_block.locator #pylint: disable=attribute-defined-outside-init self.library_content_page = LibraryContentXBlockWrapper(self.browser, block_id) self.library_content_page.wait_for_page() 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()
class CertificateProgressPageTest(UniqueCourseTest): """ Tests for verifying Certificate info on Progress tab of course page. """ def setUp(self): super(CertificateProgressPageTest, self).setUp() # set same course number as we have in fixture json self.course_info['number'] = "3355358979513794782079645765720179311111" test_certificate_config = { 'id': 1, 'name': 'Certificate name', 'description': 'Certificate description', 'course_title': 'Course title override', 'signatories': [], 'version': 1, 'is_active': True } course_settings = {'certificates': test_certificate_config} self.course_fixture = CourseFixture(self.course_info["org"], self.course_info["number"], self.course_info["run"], self.course_info["display_name"], settings=course_settings) self.course_fixture.add_advanced_settings( {"cert_html_view_enabled": { "value": "true" }}) self.course_fixture.add_update( CourseUpdateDesc(date='January 29, 2014', content='Test course update1')) self.course_fixture.add_children( XBlockFixtureDesc('static_tab', 'Test Static Tab'), XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection', grader_type='Final Exam').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 1', data=load_data_str('multiple_choice.xml')), XBlockFixtureDesc('html', 'Test HTML'), )), XBlockFixtureDesc('chapter', 'Test Section 2').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection 2', grader_type='Midterm Exam').add_children( XBlockFixtureDesc( 'problem', 'Test Problem 2', data=load_data_str('formula_problem.xml')), ))) self.course_fixture.install() self.user_id = "99" # we have created a user with this id in fixture self.cert_fixture = CertificateConfigFixture(self.course_id, test_certificate_config) self.course_info_page = CourseInfoPage(self.browser, self.course_id) self.progress_page = ProgressPage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_home_page = CourseHomePage(self.browser, self.course_id) self.tab_nav = TabNavPage(self.browser) def log_in_as_unique_user(self): """ Log in as a valid lms user. """ AutoAuthPage(self.browser, username="******", email="*****@*****.**", password="******", course_id=self.course_id).visit() def test_progress_page_has_view_certificate_button(self): """ Scenario: View Certificate option should be present on Course Progress menu if the user is awarded a certificate. And their should be no padding around the box containing certificate info. (See SOL-1196 for details on this) As a Student Given there is a course with certificate configuration And I have passed the course and certificate is generated When I go on the Progress tab for the course Then I should see a 'View Certificate' button And their should be no padding around Certificate info box. """ self.cert_fixture.install() self.log_in_as_unique_user() self.complete_course_problems() self.course_info_page.visit() self.tab_nav.go_to_tab('Progress') self.assertTrue( self.progress_page.q(css='.auto-cert-message').first.visible) actual_padding = get_element_padding(self.progress_page, '.wrapper-msg.wrapper-auto-cert') actual_padding = [ int(padding) for padding in actual_padding.itervalues() ] expected_padding = [0, 0, 0, 0] # Verify that their is no padding around the box containing certificate info. self.assertEqual(actual_padding, expected_padding) def complete_course_problems(self): """ Complete Course Problems. Problems were added in the setUp """ # self.course_info_page.visit() # self.tab_nav.go_to_tab('Course') # # # TODO: TNL-6546: Remove extra visit call. self.course_home_page.visit() # Navigate to Test Subsection in Test Section Section self.course_home_page.outline.go_to_section('Test Section', 'Test Subsection') # Navigate to Test Problem 1 self.courseware_page.nav.go_to_vertical('Test Problem 1') # Select correct value for from select menu self.courseware_page.q( css='select option[value="{}"]'.format('blue')).first.click() # Select correct radio button for the answer self.courseware_page.q( css='fieldset div.field:nth-child(4) input').nth(0).click() # Select correct radio buttons for the answer self.courseware_page.q( css='fieldset div.field:nth-child(2) input').nth(1).click() self.courseware_page.q( css='fieldset div.field:nth-child(4) input').nth(1).click() # Submit the answer self.courseware_page.q(css='button.submit').click() self.courseware_page.wait_for_ajax() # Navigate to the 'Test Subsection 2' of 'Test Section 2' self.course_home_page.visit() self.course_home_page.outline.go_to_section('Test Section 2', 'Test Subsection 2') # Navigate to Test Problem 2 self.courseware_page.nav.go_to_vertical('Test Problem 2') # Fill in the answer of the problem self.courseware_page.q( css='input[id^=input_][id$=_2_1]').fill('A*x^2 + sqrt(y)') # Submit the answer self.courseware_page.q(css='button.submit').click() self.courseware_page.wait_for_ajax()
class VideoBaseTest(UniqueCourseTest): """ Base class for tests of the Video Player Sets up the course and provides helper functions for the Video tests. """ def setUp(self): """ Initialization of pages and course fixture for video tests """ super(VideoBaseTest, self).setUp() self.longMessage = True self.video = VideoPage(self.browser) self.tab_nav = TabNavPage(self.browser) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_info_page = CourseInfoPage(self.browser, self.course_id) self.auth_page = AutoAuthPage(self.browser, course_id=self.course_id) self.course_fixture = CourseFixture(self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) self.metadata = None self.assets = [] self.contents_of_verticals = None self.youtube_configuration = {} self.user_info = {} # reset youtube stub server self.addCleanup(YouTubeStubConfig.reset) def navigate_to_video(self): """ Prepare the course and get to the video and render it """ self._install_course_fixture() self._navigate_to_courseware_video_and_render() def navigate_to_video_no_render(self): """ Prepare the course and get to the video unit however do not wait for it to render, because the has been an error. """ self._install_course_fixture() self._navigate_to_courseware_video_no_render() def _install_course_fixture(self): """ Install the course fixture that has been defined """ if self.assets: self.course_fixture.add_asset(self.assets) chapter_sequential = XBlockFixtureDesc('sequential', 'Test Section') chapter_sequential.add_children(*self._add_course_verticals()) chapter = XBlockFixtureDesc( 'chapter', 'Test Chapter').add_children(chapter_sequential) self.course_fixture.add_children(chapter) self.course_fixture.install() if len(self.youtube_configuration) > 0: YouTubeStubConfig.configure(self.youtube_configuration) def _add_course_verticals(self): """ Create XBlockFixtureDesc verticals :return: a list of XBlockFixtureDesc """ xblock_verticals = [] _contents_of_verticals = self.contents_of_verticals # Video tests require at least one vertical with a single video. if not _contents_of_verticals: _contents_of_verticals = [[{ 'display_name': 'Video', 'metadata': self.metadata }]] for vertical_index, vertical in enumerate(_contents_of_verticals): xblock_verticals.append( self._create_single_vertical(vertical, vertical_index)) return xblock_verticals def _create_single_vertical(self, vertical_contents, vertical_index): """ Create a single course vertical of type XBlockFixtureDesc with category `vertical`. A single course vertical can contain single or multiple video modules. :param vertical_contents: a list of items for the vertical to contain :param vertical_index: index for the vertical display name :return: XBlockFixtureDesc """ xblock_course_vertical = XBlockFixtureDesc( 'vertical', 'Test Vertical-{0}'.format(vertical_index)) for video in vertical_contents: xblock_course_vertical.add_children( XBlockFixtureDesc('video', video['display_name'], metadata=video.get('metadata'))) return xblock_course_vertical def _navigate_to_courseware_video(self): """ Register for the course and navigate to the video unit """ self.auth_page.visit() self.user_info = self.auth_page.user_info self.courseware_page.visit() def _navigate_to_courseware_video_and_render(self): """ Wait for the video player to render """ self._navigate_to_courseware_video() self.video.wait_for_video_player_render() def _navigate_to_courseware_video_no_render(self): """ Wait for the video Xmodule but not for rendering """ self._navigate_to_courseware_video() self.video.wait_for_video_class() def metadata_for_mode(self, player_mode, additional_data=None): """ Create a dictionary for video player configuration according to `player_mode` :param player_mode (str): Video player mode :param additional_data (dict): Optional additional metadata. :return: dict """ metadata = {} youtube_ids = { 'youtube_id_1_0': '', 'youtube_id_0_75': '', 'youtube_id_1_25': '', 'youtube_id_1_5': '', } if player_mode == 'html5': metadata.update(youtube_ids) metadata.update({'html5_sources': HTML5_SOURCES}) if player_mode == 'youtube_html5': metadata.update({ 'html5_sources': HTML5_SOURCES, }) if player_mode == 'youtube_html5_unsupported_video': metadata.update({'html5_sources': HTML5_SOURCES_INCORRECT}) if player_mode == 'html5_unsupported_video': metadata.update(youtube_ids) metadata.update({'html5_sources': HTML5_SOURCES_INCORRECT}) if player_mode == 'hls': metadata.update(youtube_ids) metadata.update({ 'html5_sources': HLS_SOURCES, }) if player_mode == 'html5_and_hls': metadata.update(youtube_ids) metadata.update({ 'html5_sources': HTML5_SOURCES + HLS_SOURCES, }) if additional_data: metadata.update(additional_data) return metadata def go_to_sequential_position(self, position): """ Navigate to sequential specified by `video_display_name` """ self.courseware_page.go_to_sequential_position(position) self.video.wait_for_video_player_render()
class LibraryContentTestBase(UniqueCourseTest): """ Base class for library content block tests """ USERNAME = "******" EMAIL = "*****@*****.**" STAFF_USERNAME = "******" STAFF_EMAIL = "*****@*****.**" def populate_library_fixture(self, library_fixture): """ To be overwritten by subclassed tests. Used to install a library to run tests on. """ def setUp(self): """ Set up library, course and library content XBlock """ super(LibraryContentTestBase, self).setUp() 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']) self.library_fixture = LibraryFixture( 'test_org', self.unique_id, 'Test Library {}'.format(self.unique_id)) self.populate_library_fixture(self.library_fixture) self.library_fixture.install() self.library_info = self.library_fixture.library_info self.library_key = self.library_fixture.library_key # Install a course with library content xblock self.course_fixture = CourseFixture(self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) library_content_metadata = { 'source_library_id': unicode(self.library_key), 'mode': 'random', 'max_count': 1, } self.lib_block = XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata) self.course_fixture.add_children( XBlockFixtureDesc('chapter', SECTION_NAME).add_children( XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children( XBlockFixtureDesc('vertical', UNIT_NAME).add_children( self.lib_block)))) self.course_fixture.install() def _change_library_content_settings(self, count=1, capa_type=None): """ Performs library block refresh in Studio, configuring it to show {count} children """ unit_page = self._go_to_unit_page(True) library_container_block = StudioLibraryContainerXBlockWrapper.from_xblock_wrapper( unit_page.xblocks[1]) library_container_block.edit() editor = StudioLibraryContentEditor(self.browser, library_container_block.locator) editor.count = count if capa_type is not None: editor.capa_type = capa_type editor.save() self._go_to_unit_page(change_login=False) unit_page.wait_for_page() unit_page.publish_action.click() unit_page.wait_for_ajax() self.assertIn("Published and Live", unit_page.publish_title) @property def library_xblocks_texts(self): """ Gets texts of all xblocks in library """ return frozenset(child.data for child in self.library_fixture.children) def _go_to_unit_page(self, change_login=True): """ Open unit page in Studio """ if change_login: LogoutPage(self.browser).visit() self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) self.studio_course_outline.visit() subsection = self.studio_course_outline.section( SECTION_NAME).subsection(SUBSECTION_NAME) return subsection.expand_subsection().unit(UNIT_NAME).go_to() def _goto_library_block_page(self, block_id=None): """ Open library page in LMS """ self.courseware_page.visit() paragraphs = self.courseware_page.q(css='.course-content p').results if not paragraphs: course_home_page = CourseHomePage(self.browser, self.course_id) course_home_page.visit() course_home_page.outline.go_to_section_by_index(0, 0) block_id = block_id if block_id is not None else self.lib_block.locator #pylint: disable=attribute-defined-outside-init self.library_content_page = LibraryContentXBlockWrapper( self.browser, block_id) self.library_content_page.wait_for_page() 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 is_browser_on_page(self): if not CoursewarePage.is_browser_on_page(self): return False return StaffPreviewPage.is_browser_on_page(self)
class VideoLicenseTest(StudioCourseTest): """ Tests for video module-level licensing (that is, setting the license, for a specific video module, to All Rights Reserved or Creative Commons) """ def setUp(self): # pylint: disable=arguments-differ super(VideoLicenseTest, self).setUp() self.lms_courseware = CoursewarePage( self.browser, self.course_id, ) self.studio_course_outline = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) # used by StudioCourseTest.setUp() def populate_course_fixture(self, course_fixture): """ Create a course with a single chapter. That chapter has a single section. That section has a single vertical. That vertical has a single video element. """ video_block = XBlockFixtureDesc('video', "Test Video") vertical = XBlockFixtureDesc('vertical', "Test Vertical") vertical.add_children(video_block) sequential = XBlockFixtureDesc('sequential', "Test Section") sequential.add_children(vertical) chapter = XBlockFixtureDesc('chapter', "Test Chapter") chapter.add_children(sequential) self.course_fixture.add_children(chapter) def test_empty_license(self): """ When I visit the LMS courseware, I can see that the video is present but it has no license displayed by default. """ self.lms_courseware.visit() video = self.lms_courseware.q(css=".vert .xblock .video") self.assertTrue(video.is_present()) video_license = self.lms_courseware.q( css=".vert .xblock.xmodule_VideoModule .xblock-license") self.assertFalse(video_license.is_present()) def test_arr_license(self): """ When I edit a video element in Studio, I can set an "All Rights Reserved" license on that video element. When I visit the LMS courseware, I can see that the video is present and that it has "All Rights Reserved" displayed for the license. """ self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at(0).subsection_at(0) subsection.expand_subsection() unit = subsection.unit_at(0) container_page = unit.go_to() container_page.edit() video = [ xb for xb in container_page.xblocks if xb.name == "Test Video" ][0] video.open_advanced_tab() video.set_license('all-rights-reserved') video.save_settings() container_page.publish_action.click() self.lms_courseware.visit() video = self.lms_courseware.q(css=".vert .xblock .video") self.assertTrue(video.is_present()) video_license_css = ".vert .xblock.xmodule_VideoModule .xblock-license" self.lms_courseware.wait_for_element_presence( video_license_css, "Video module license block is present") video_license = self.lms_courseware.q(css=video_license_css) self.assertEqual(video_license.text[0], "© All Rights Reserved") def test_cc_license(self): """ When I edit a video element in Studio, I can set a "Creative Commons" license on that video element. When I visit the LMS courseware, I can see that the video is present and that it has "Some Rights Reserved" displayed for the license. """ self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at(0).subsection_at(0) subsection.expand_subsection() unit = subsection.unit_at(0) container_page = unit.go_to() container_page.edit() video = [ xb for xb in container_page.xblocks if xb.name == "Test Video" ][0] video.open_advanced_tab() video.set_license('creative-commons') video.save_settings() container_page.publish_action.click() self.lms_courseware.visit() video = self.lms_courseware.q(css=".vert .xblock .video") self.assertTrue(video.is_present()) video_license_css = ".vert .xblock.xmodule_VideoModule .xblock-license" self.lms_courseware.wait_for_element_presence( video_license_css, "Video module license block is present") video_license = self.lms_courseware.q(css=video_license_css) self.assertIn("Some Rights Reserved", video_license.text[0])
def is_browser_on_page(self): if not CoursewarePage.is_browser_on_page(self): return False return StaffPreviewPage.is_browser_on_page(self)
class CourseOutlinePage(PageObject): """ Course outline fragment of page. """ url = None def __init__(self, browser, parent_page): super(CourseOutlinePage, self).__init__(browser) self.parent_page = parent_page self.courseware_page = CoursewarePage(self.browser, self.parent_page.course_id) def is_browser_on_page(self): return self.parent_page.is_browser_on_page @property def sections(self): """ Return a dictionary representation of sections and subsections. Example: { 'Introduction': ['Course Overview'], 'Week 1': ['Lesson 1', 'Lesson 2', 'Homework'] 'Final Exam': ['Final Exam'] } You can use these titles in `go_to_section` to navigate to the section. """ # Dict to store the result outline_dict = dict() section_titles = self._section_titles() # Get the section titles for each chapter for sec_index, sec_title in enumerate(section_titles): if len(section_titles) < 1: self.warning( "Could not find subsections for '{0}'".format(sec_title)) else: # Add one to convert list index (starts at 0) to CSS index (starts at 1) outline_dict[sec_title] = self._subsection_titles(sec_index + 1) return outline_dict def go_to_section(self, section_title, subsection_title): """ Go to the section in the courseware. Every section must have at least one subsection, so specify both the section and subsection title. Example: go_to_section("Week 1", "Lesson 1") """ # Get the section by index try: section_index = self._section_titles().index(section_title) except ValueError: self.warning("Could not find section '{0}'".format(section_title)) return # Get the subsection by index try: subsection_index = self._subsection_titles( section_index + 1).index(subsection_title) except ValueError: msg = "Could not find subsection '{0}' in section '{1}'".format( subsection_title, section_title) self.warning(msg) return # Convert list indices (start at zero) to CSS indices (start at 1) subsection_css = ( ".outline-item.section:nth-of-type({0}) .subsection:nth-of-type({1}) .outline-item" ).format(section_index + 1, subsection_index + 1) # Click the subsection and ensure that the page finishes reloading self.q(css=subsection_css).first.click() self.courseware_page.wait_for_page() # TODO: TNL-6546: Remove this if/visit_unified_course_view if self.parent_page.unified_course_view: self.courseware_page.nav.visit_unified_course_view() self._wait_for_course_section(section_title, subsection_title) def _section_titles(self): """ Return a list of all section titles on the page. """ section_css = '.section-name span' return self.q(css=section_css).map(lambda el: el.text.strip()).results def _subsection_titles(self, section_index): """ Return a list of all subsection titles on the page for the section at index `section_index` (starts at 1). """ # Retrieve the subsection title for the section # Add one to the list index to get the CSS index, which starts at one subsection_css = ( # TODO: TNL-6387: Will need to switch to this selector for subsections # ".outline-item.section:nth-of-type({0}) .subsection span:nth-of-type(1)" ".outline-item.section:nth-of-type({0}) .subsection a" ).format(section_index) return self.q(css=subsection_css).map( lambda el: el.get_attribute('innerHTML').strip()).results def _wait_for_course_section(self, section_title, subsection_title): """ Ensures the user navigates to the course content page with the correct section and subsection. """ self.wait_for( promise_check_func=lambda: self.courseware_page.nav.is_on_section( section_title, subsection_title), description= "Waiting for course page with section '{0}' and subsection '{1}'". format(section_title, subsection_title))
class ContentLicenseTest(StudioCourseTest): """ Tests for course-level licensing (that is, setting the license, for an entire course's content, to All Rights Reserved or Creative Commons) """ def setUp(self): # pylint: disable=arguments-differ super(ContentLicenseTest, self).setUp() self.outline_page = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.settings_page = SettingsPage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.lms_courseware = CoursewarePage( self.browser, self.course_id, ) self.settings_page.visit() def test_empty_license(self): """ When I visit the Studio settings page, I see that the course license is "All Rights Reserved" by default. Then I visit the LMS courseware page, and I see that the default course license is displayed. """ self.assertEqual(self.settings_page.course_license, "All Rights Reserved") self.lms_courseware.visit() self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved") def test_arr_license(self): """ When I visit the Studio settings page, and I set the course license to "All Rights Reserved", and I refresh the page, I see that the course license is "All Rights Reserved". Then I visit the LMS courseware page, and I see that the course license is "All Rights Reserved". """ self.settings_page.course_license = "All Rights Reserved" self.settings_page.save_changes() self.settings_page.refresh_and_wait_for_load() self.assertEqual(self.settings_page.course_license, "All Rights Reserved") self.lms_courseware.visit() self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved") def test_cc_license(self): """ When I visit the Studio settings page, and I set the course license to "Creative Commons", and I refresh the page, I see that the course license is "Creative Commons". Then I visit the LMS courseware page, and I see that the course license is "Some Rights Reserved". """ self.settings_page.course_license = "Creative Commons" self.settings_page.save_changes() self.settings_page.refresh_and_wait_for_load() self.assertEqual(self.settings_page.course_license, "Creative Commons") self.lms_courseware.visit() # The course_license text will include a bunch of screen reader text to explain # the selected options self.assertIn("Some Rights Reserved", self.lms_courseware.course_license)
def test_visit_coursware(self): """ Produce a HAR for loading the Coursware page. """ courseware_page = CoursewarePage(self.browser, self.course_id) self._make_har_file(courseware_page)
class AnnotatableProblemTest(UniqueCourseTest): """ Tests for annotation components. """ USERNAME = "******" EMAIL = "*****@*****.**" DATA_TEMPLATE = dedent("""\ <annotatable> <instructions>Instruction text</instructions> <p>{}</p> </annotatable> """) ANNOTATION_TEMPLATE = dedent("""\ Before {0}. <annotation title="region {0}" body="Comment {0}" highlight="yellow" problem="{0}"> Region Contents {0} </annotation> After {0}. """) PROBLEM_TEMPLATE = dedent("""\ <problem max_attempts="1" weight=""> <annotationresponse> <annotationinput> <title>Question {number}</title> <text>Region Contents {number}</text> <comment>What number is this region?</comment> <comment_prompt>Type your response below:</comment_prompt> <tag_prompt>What number is this region?</tag_prompt> <options> {options} </options> </annotationinput> </annotationresponse> <solution> This problem is checking region {number} </solution> </problem> """) OPTION_TEMPLATE = """<option choice="{correctness}">{number}</option>""" def setUp(self): super(AnnotatableProblemTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with two annotations and two annotations problems. course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.annotation_count = 2 course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Annotation Vertical').add_children( XBlockFixtureDesc('annotatable', 'Test Annotation Module', data=self.DATA_TEMPLATE.format("\n".join( self.ANNOTATION_TEMPLATE.format(i) for i in xrange(self.annotation_count) ))), XBlockFixtureDesc('problem', 'Test Annotation Problem 0', data=self.PROBLEM_TEMPLATE.format(number=0, options="\n".join( self.OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, 0)) for k in xrange(self.annotation_count) ))), XBlockFixtureDesc('problem', 'Test Annotation Problem 1', data=self.PROBLEM_TEMPLATE.format(number=1, options="\n".join( self.OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, 1)) for k in xrange(self.annotation_count) ))) ) ) ) ).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit() def _goto_annotation_component_page(self): """ Open annotation component page with assertion. """ self.courseware_page.visit() annotation_component_page = AnnotationComponentPage(self.browser) self.assertEqual( annotation_component_page.component_name, 'Test Annotation Module'.format() ) return annotation_component_page def test_annotation_component(self): """ Test annotation components links to annotation problems. """ annotation_component_page = self._goto_annotation_component_page() # This will avoid scrolling related problems on different browsers and instead directly jump on the problem disable_animations(annotation_component_page) for i in xrange(self.annotation_count): annotation_component_page.click_reply_annotation(i) self.assertTrue(annotation_component_page.check_scroll_to_problem()) annotation_component_page.answer_problem() self.assertTrue(annotation_component_page.check_feedback()) annotation_component_page.click_return_to_annotation() self.assertTrue(annotation_component_page.check_scroll_to_annotation())
def __init__(self, browser, course_id): CoursewarePage.__init__(self, browser, course_id) StaffPreviewPage.__init__(self, browser)
def __init__(self, browser, parent_page): super(CourseOutlinePage, self).__init__(browser) self.parent_page = parent_page self.courseware_page = CoursewarePage(self.browser, self.parent_page.course_id)
class BookmarksTestMixin(EventsTestMixin, UniqueCourseTest): """ Mixin with helper methods for testing Bookmarks. """ USERNAME = "******" EMAIL = "*****@*****.**" def setUp(self): super(BookmarksTestMixin, self).setUp() self.studio_course_outline_page = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_home_page = CourseHomePage(self.browser, self.course_id) self.bookmarks_page = BookmarksPage(self.browser, self.course_id) # Get session to be used for bookmarking units self.session = requests.Session() params = { 'username': self.USERNAME, 'email': self.EMAIL, 'course_id': self.course_id } response = self.session.get(BASE_URL + "/auto_auth", params=params) self.assertTrue(response.ok, "Failed to get session") def setup_test(self, num_chapters=2): """ Setup test settings. Arguments: num_chapters: number of chapters to create in course """ self.create_course_fixture(num_chapters) # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id).visit() self.courseware_page.visit() def create_course_fixture(self, num_chapters): """ Create course fixture Arguments: num_chapters: number of chapters to create """ self.course_fixture = CourseFixture( # pylint: disable=attribute-defined-outside-init self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) xblocks = [] for index in range(num_chapters): xblocks += [ XBlockFixtureDesc( 'chapter', 'TestSection{}'.format(index)).add_children( XBlockFixtureDesc( 'sequential', 'TestSubsection{}'.format(index)).add_children( XBlockFixtureDesc( 'vertical', 'TestVertical{}'.format(index)))) ] self.course_fixture.add_children(*xblocks).install() def verify_event_data(self, event_type, event_data): """ Verify emitted event data. Arguments: event_type: expected event type event_data: expected event data """ actual_events = self.wait_for_events( event_filter={'event_type': event_type}, number_of_matches=1) self.assert_events_match(event_data, actual_events) def _bookmark_unit(self, location): """ Bookmark a unit Arguments: location (str): unit location """ _headers = { 'Content-type': 'application/json', 'X-CSRFToken': self.session.cookies['csrftoken'], } params = {'course_id': self.course_id} data = json.dumps({'usage_id': location}) response = self.session.post(BASE_URL + '/api/bookmarks/v1/bookmarks/', data=data, params=params, headers=_headers) self.assertTrue(response.ok, "Failed to bookmark unit") def bookmark_units(self, num_units): """ Bookmark first `num_units` units Arguments: num_units(int): Number of units to bookmarks """ xblocks = self.course_fixture.get_nested_xblocks(category="vertical") for index in range(num_units): self._bookmark_unit(xblocks[index].locator)
class VideoBaseTest(UniqueCourseTest): """ Base class for tests of the Video Player Sets up the course and provides helper functions for the Video tests. """ def setUp(self): """ Initialization of pages and course fixture for video tests """ super(VideoBaseTest, self).setUp() self.longMessage = True self.video = VideoPage(self.browser) self.tab_nav = TabNavPage(self.browser) self.courseware_page = CoursewarePage(self.browser, self.course_id) self.course_info_page = CourseInfoPage(self.browser, self.course_id) self.auth_page = AutoAuthPage(self.browser, course_id=self.course_id) self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) self.metadata = None self.assets = [] self.contents_of_verticals = None self.youtube_configuration = {} self.user_info = {} # reset youtube stub server self.addCleanup(YouTubeStubConfig.reset) def navigate_to_video(self): """ Prepare the course and get to the video and render it """ self._install_course_fixture() self._navigate_to_courseware_video_and_render() def navigate_to_video_no_render(self): """ Prepare the course and get to the video unit however do not wait for it to render, because the has been an error. """ self._install_course_fixture() self._navigate_to_courseware_video_no_render() def _install_course_fixture(self): """ Install the course fixture that has been defined """ if self.assets: self.course_fixture.add_asset(self.assets) chapter_sequential = XBlockFixtureDesc('sequential', 'Test Section') chapter_sequential.add_children(*self._add_course_verticals()) chapter = XBlockFixtureDesc('chapter', 'Test Chapter').add_children(chapter_sequential) self.course_fixture.add_children(chapter) self.course_fixture.install() if len(self.youtube_configuration) > 0: YouTubeStubConfig.configure(self.youtube_configuration) def _add_course_verticals(self): """ Create XBlockFixtureDesc verticals :return: a list of XBlockFixtureDesc """ xblock_verticals = [] _contents_of_verticals = self.contents_of_verticals # Video tests require at least one vertical with a single video. if not _contents_of_verticals: _contents_of_verticals = [[{'display_name': 'Video', 'metadata': self.metadata}]] for vertical_index, vertical in enumerate(_contents_of_verticals): xblock_verticals.append(self._create_single_vertical(vertical, vertical_index)) return xblock_verticals def _create_single_vertical(self, vertical_contents, vertical_index): """ Create a single course vertical of type XBlockFixtureDesc with category `vertical`. A single course vertical can contain single or multiple video modules. :param vertical_contents: a list of items for the vertical to contain :param vertical_index: index for the vertical display name :return: XBlockFixtureDesc """ xblock_course_vertical = XBlockFixtureDesc('vertical', u'Test Vertical-{0}'.format(vertical_index)) for video in vertical_contents: xblock_course_vertical.add_children( XBlockFixtureDesc('video', video['display_name'], metadata=video.get('metadata'))) return xblock_course_vertical def _navigate_to_courseware_video(self): """ Register for the course and navigate to the video unit """ self.auth_page.visit() self.user_info = self.auth_page.user_info self.courseware_page.visit() def _navigate_to_courseware_video_and_render(self): """ Wait for the video player to render """ self._navigate_to_courseware_video() self.video.wait_for_video_player_render() def _navigate_to_courseware_video_no_render(self): """ Wait for the video Xmodule but not for rendering """ self._navigate_to_courseware_video() self.video.wait_for_video_class() def metadata_for_mode(self, player_mode, additional_data=None): """ Create a dictionary for video player configuration according to `player_mode` :param player_mode (str): Video player mode :param additional_data (dict): Optional additional metadata. :return: dict """ metadata = {} youtube_ids = { 'youtube_id_1_0': '', 'youtube_id_0_75': '', 'youtube_id_1_25': '', 'youtube_id_1_5': '', } if player_mode == 'html5': metadata.update(youtube_ids) metadata.update({ 'html5_sources': HTML5_SOURCES }) if player_mode == 'youtube_html5': metadata.update({ 'html5_sources': HTML5_SOURCES, }) if player_mode == 'youtube_html5_unsupported_video': metadata.update({ 'html5_sources': HTML5_SOURCES_INCORRECT }) if player_mode == 'html5_unsupported_video': metadata.update(youtube_ids) metadata.update({ 'html5_sources': HTML5_SOURCES_INCORRECT }) if player_mode == 'hls': metadata.update(youtube_ids) metadata.update({ 'html5_sources': HLS_SOURCES, }) if player_mode == 'html5_and_hls': metadata.update(youtube_ids) metadata.update({ 'html5_sources': HTML5_SOURCES + HLS_SOURCES, }) if additional_data: metadata.update(additional_data) return metadata def go_to_sequential_position(self, position): """ Navigate to sequential specified by `video_display_name` """ self.courseware_page.go_to_sequential_position(position) self.video.wait_for_video_player_render()
class DragAndDropXblockWithMixinsTest(UniqueCourseTest): """ Test Suite to verify various behaviors of DragAndDrop Xblock on the LMS. """ def setUp(self): super(DragAndDropXblockWithMixinsTest, self).setUp() self.username = "******".format(uuid=self.unique_id[0:8]) self.email = "{username}@example.com".format(username=self.username) self.password = "******" self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with a hierarchy and problems self.course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'], start_date=datetime.now() + timedelta(days=10) ) self.browser.set_window_size(1024, 1024) def setup_sequential(self, metadata): """ Setup a sequential with DnD problem, alongwith the metadata provided. This method will allow to customize the sequential, such as changing the due date for individual tests. """ problem = self.get_problem() sequential = self.get_sequential(metadata=metadata) self.course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( sequential.add_children(problem) ) ).install() # Auto-auth register for the course. AutoAuthPage( self.browser, username=self.username, email=self.email, password=self.password, course_id=self.course_id, staff=True ).visit() def format_date(self, date_value): """ Get the date in isoformat as this is required format to add date data in the sequential. """ return date_value.isoformat() def get_problem(self): """ Creating a DnD problem with assessment mode """ return XBlockFixtureDesc('drag-and-drop-v2', 'DnD', metadata={'mode': "assessment"}) def get_sequential(self, metadata=None): return XBlockFixtureDesc('sequential', 'Test Subsection', metadata=metadata) @ddt.data( (datetime.now(), True), (datetime.now() - timedelta(days=1), True), (datetime.now() + timedelta(days=1), False) ) @ddt.unpack def test_submit_button_status_with_due_date(self, due_date, is_button_disabled): """ Scenario: Test that DnD submit button will be enabled if section is not past due. Given I have a sequential in instructor-paced course And a DnD problem with assessment mode is present in the sequential When I visit the problem Then the submit button should be present And button should be disabled as some item needs to be on a zone When I drag an item to a zone Then submit button will be enabled if due date has not passed, else disabled """ problem_page = DragAndDropPage(self.browser) self.setup_sequential(metadata={'due': self.format_date(due_date)}) self.courseware_page.visit() self.assertTrue(problem_page.is_submit_button_present()) self.assertTrue(problem_page.is_submit_disabled()) problem_page.drag_item_to_zone(0, 'middle') self.assertEqual(is_button_disabled, problem_page.is_submit_disabled()) def test_submit_button_when_pacing_change_self_paced(self): """ Scenario: For a self-paced course, the submit button of DnD problems will be be enabled, regardless of the subsection due date. Given a DnD problem in a subsection with past due date And the course is instructor-paced Then the submit button will remain disabled after initial drag When the pacing is changed to self-paced Then the submit button is not disabled anymore """ problem_page = DragAndDropPage(self.browser) self.setup_sequential(metadata={'due': self.format_date(datetime.now())}) self.courseware_page.visit() problem_page.drag_item_to_zone(0, 'middle') self.assertTrue(problem_page.is_submit_disabled()) self.course_fixture.add_course_details({'self_paced': True}) self.course_fixture.configure_course() self.courseware_page.visit() self.assertFalse(problem_page.is_submit_disabled())
def __init__(self, browser, course_id): CoursewarePage.__init__(self, browser, course_id) StaffPreviewPage.__init__(self, browser)
def setUp(self): super(ConditionalTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) AutoAuthPage(self.browser, course_id=self.course_id, staff=False).visit()
class ContentLicenseTest(StudioCourseTest): """ Tests for course-level licensing (that is, setting the license, for an entire course's content, to All Rights Reserved or Creative Commons) """ def setUp(self): # pylint: disable=arguments-differ super(ContentLicenseTest, self).setUp() self.outline_page = CourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.settings_page = SettingsPage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) self.lms_courseware = CoursewarePage( self.browser, self.course_id, ) self.settings_page.visit() def test_empty_license(self): """ When I visit the Studio settings page, I see that the course license is "All Rights Reserved" by default. Then I visit the LMS courseware page, and I see that the default course license is displayed. """ self.assertEqual(self.settings_page.course_license, "All Rights Reserved") self.lms_courseware.visit() self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved") def test_arr_license(self): """ When I visit the Studio settings page, and I set the course license to "All Rights Reserved", and I refresh the page, I see that the course license is "All Rights Reserved". Then I visit the LMS courseware page, and I see that the course license is "All Rights Reserved". """ self.settings_page.course_license = "All Rights Reserved" self.settings_page.save_changes() self.settings_page.refresh_and_wait_for_load() self.assertEqual(self.settings_page.course_license, "All Rights Reserved") self.lms_courseware.visit() self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved") def test_cc_license(self): """ When I visit the Studio settings page, and I set the course license to "Creative Commons", and I refresh the page, I see that the course license is "Creative Commons". Then I visit the LMS courseware page, and I see that the course license is "Some Rights Reserved". """ self.settings_page.course_license = "Creative Commons" self.settings_page.save_changes() self.settings_page.refresh_and_wait_for_load() self.assertEqual(self.settings_page.course_license, "Creative Commons") self.lms_courseware.visit() # The course_license text will include a bunch of screen reader text to explain # the selected options self.assertIn("Some Rights Reserved", self.lms_courseware.course_license)
class ConditionalTest(UniqueCourseTest): """ Test the conditional module in the lms. """ shard = 23 def setUp(self): super(ConditionalTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) AutoAuthPage(self.browser, course_id=self.course_id, staff=False).visit() def install_course_fixture(self, block_type='problem'): """ Install a course fixture """ course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'], ) vertical = XBlockFixtureDesc('vertical', 'Test Unit') # populate the course fixture with the right conditional modules course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children(vertical))) course_fixture.install() # Construct conditional block source_block = None conditional_attr = None conditional_value = None if block_type == 'problem': problem_factory = StringResponseXMLFactory() problem_xml = problem_factory.build_xml( question_text='The answer is "correct string"', case_sensitive=False, answer='correct string', ), problem = XBlockFixtureDesc('problem', 'Test Problem', data=problem_xml[0]) source_block = problem conditional_attr = 'attempted' conditional_value = 'True' elif block_type == 'poll': poll = XBlockFixtureDesc( 'poll_question', 'Conditional Poll', question='Is this a good poll?', answers=[{ 'id': 'yes', 'text': POLL_ANSWER }, { 'id': 'no', 'text': 'Of course not!' }], ) conditional_attr = 'poll_answer' conditional_value = 'yes' source_block = poll else: raise NotImplementedError() course_fixture.create_xblock(vertical.locator, source_block) # create conditional conditional = XBlockFixtureDesc('conditional', 'Test Conditional', sources_list=[source_block.locator], conditional_attr=conditional_attr, conditional_value=conditional_value) result_block = XBlockFixtureDesc( 'html', 'Conditional Contents', data='<html><div class="hidden-contents">Hidden Contents</p></html>' ) course_fixture.create_xblock(vertical.locator, conditional) course_fixture.create_xblock(conditional.locator, result_block) def test_conditional_hides_content(self): self.install_course_fixture() self.courseware_page.visit() conditional_page = ConditionalPage(self.browser) self.assertFalse(conditional_page.is_content_visible()) def test_conditional_displays_content(self): self.install_course_fixture() self.courseware_page.visit() # Answer the problem problem_page = ProblemPage(self.browser) problem_page.fill_answer('correct string') problem_page.click_submit() # The conditional does not update on its own, so we need to reload the page. self.courseware_page.visit() # Verify that we can see the content. conditional_page = ConditionalPage(self.browser) self.assertTrue(conditional_page.is_content_visible()) def test_conditional_handles_polls(self): self.install_course_fixture(block_type='poll') self.courseware_page.visit() # Fill in the conditional page poll conditional_page = ConditionalPage(self.browser) conditional_page.fill_in_poll() # The conditional does not update on its own, so we need to reload the page. self.courseware_page.visit() self.assertTrue(conditional_page.is_content_visible())
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)" 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, 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()) 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())
def setup_thread_page(self, thread_id): CoursewarePage(self.browser, self.course_id).visit() self.show_thread(thread_id)
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())
class VisibleToStaffOnlyTest(UniqueCourseTest): """ Tests that content with visible_to_staff_only set to True cannot be viewed by students. """ def setUp(self): super(VisibleToStaffOnlyTest, self).setUp() course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Subsection With Locked Unit').add_children( XBlockFixtureDesc('vertical', 'Locked Unit', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('html', 'Html Child in locked unit', data="<html>Visible only to staff</html>"), ), XBlockFixtureDesc('vertical', 'Unlocked Unit').add_children( XBlockFixtureDesc('html', 'Html Child in unlocked unit', data="<html>Visible only to all</html>"), ) ), XBlockFixtureDesc('sequential', 'Unlocked Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('html', 'Html Child in visible unit', data="<html>Visible to all</html>"), ) ), XBlockFixtureDesc('sequential', 'Locked Subsection', metadata={'visible_to_staff_only': True}).add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'html', 'Html Child in locked subsection', data="<html>Visible only to staff</html>" ) ) ) ) ).install() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id) def test_visible_to_student(self): """ Scenario: Content marked 'visible_to_staff_only' is not visible for students in the course Given some of the course content has been marked 'visible_to_staff_only' And I am logged on with an authorized student account Then I can only see content without 'visible_to_staff_only' set to True """ AutoAuthPage(self.browser, username="******", email="*****@*****.**", course_id=self.course_id, staff=False).visit() self.course_home_page.visit() self.assertEqual(2, len(self.course_home_page.outline.sections['Test Section'])) self.course_home_page.outline.go_to_section("Test Section", "Subsection With Locked Unit") self.courseware_page.wait_for_page() self.assertEqual([u'Unlocked Unit'], self.courseware_page.nav.sequence_items) self.course_home_page.visit() self.course_home_page.outline.go_to_section("Test Section", "Unlocked Subsection") self.courseware_page.wait_for_page() self.assertEqual([u'Test Unit'], self.courseware_page.nav.sequence_items)