コード例 #1
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)

        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 = StaffCoursewarePage(self.browser, self.course_id)
        self.assertEqual(staff_page.staff_view_mode, 'Staff')
        return staff_page
コード例 #2
0
ファイル: test_lms.py プロジェクト: cmscom/edx-platform
    def setUp(self):
        """Create a course that is closed for enrollment, and sign in as a user."""
        super(EnrollmentClosedRedirectTest, self).setUp()
        course = CourseFixture(
            self.course_info['org'], self.course_info['number'],
            self.course_info['run'], self.course_info['display_name']
        )
        now = datetime.now(pytz.UTC)
        course.add_course_details({
            'enrollment_start': (now - timedelta(days=30)).isoformat(),
            'enrollment_end': (now - timedelta(days=1)).isoformat()
        })
        course.install()

        # Add an honor mode to the course
        ModeCreationPage(self.browser, self.course_id).visit()

        # 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()
コード例 #3
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
コード例 #4
0
    def setUp(self):
        """
        Initialize pages and install a course fixture.
        """
        super(PDFTextBooksTabTest, self).setUp()

        self.course_home_page = CourseHomePage(self.browser, self.course_id)
        self.tab_nav = TabNavPage(self.browser)

        # Install a course with TextBooks
        course_fix = CourseFixture(self.course_info['org'],
                                   self.course_info['number'],
                                   self.course_info['run'],
                                   self.course_info['display_name'])

        # Add PDF textbooks to course fixture.
        for i in range(1, 3):
            course_fix.add_textbook(
                "PDF Book {}".format(i),
                [{
                    "title": "Chapter Of Book {}".format(i),
                    "url": ""
                }])

        course_fix.install()

        # Auto-auth register for the course
        AutoAuthPage(self.browser, course_id=self.course_id).visit()
コード例 #5
0
ファイル: helpers.py プロジェクト: gopinath81/vmss
class BaseDiscussionTestCase(UniqueCourseTest, ForumsConfigMixin):
    """Base test case class for all discussions-related tests."""
    def setUp(self):
        super(BaseDiscussionTestCase, self).setUp()

        self.discussion_id = "test_discussion_{}".format(uuid4().hex)
        self.course_fixture = CourseFixture(**self.course_info)
        self.course_fixture.add_advanced_settings({
            'discussion_topics': {
                'value': {
                    'Test Discussion Topic': {
                        'id': self.discussion_id
                    }
                }
            }
        })
        self.course_fixture.install()

        self.enable_forums()

    def create_single_thread_page(self, thread_id):
        """
        Sets up a `DiscussionTabSingleThreadPage` for a given
        `thread_id`.
        """
        return DiscussionTabSingleThreadPage(self.browser, self.course_id,
                                             self.discussion_id, thread_id)
コード例 #6
0
ファイル: test_lms.py プロジェクト: fdns/eol-edx
    def setUp(self):
        """Create a course that is closed for enrollment, and sign in as a user."""
        super(EnrollmentClosedRedirectTest, self).setUp()
        course = CourseFixture(
            self.course_info['org'], self.course_info['number'],
            self.course_info['run'], self.course_info['display_name']
        )
        now = datetime.now(pytz.UTC)
        course.add_course_details({
            'enrollment_start': (now - timedelta(days=30)).isoformat(),
            'enrollment_end': (now - timedelta(days=1)).isoformat()
        })
        course.install()

        # Add an honor mode to the course
        ModeCreationPage(self.browser, self.course_id).visit()

        # 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()
コード例 #7
0
class BaseDiscussionTestCase(UniqueCourseTest, ForumsConfigMixin):
    """Base test case class for all discussions-related tests."""
    def setUp(self):
        super(BaseDiscussionTestCase, self).setUp()

        self.discussion_id = "test_discussion_{}".format(uuid4().hex)
        self.course_fixture = CourseFixture(**self.course_info)
        self.course_fixture.add_children(
            XBlockFixtureDesc("chapter", "Test Section").add_children(
                XBlockFixtureDesc("sequential", "Test Subsection").add_children(
                    XBlockFixtureDesc("vertical", "Test Unit").add_children(
                        XBlockFixtureDesc(
                            "discussion",
                            "Test Discussion",
                            metadata={"discussion_id": self.discussion_id}
                        )
                    )
                )
            )
        )
        self.course_fixture.add_advanced_settings(
            {'discussion_topics': {'value': {'General': {'id': 'course'}}}}
        )
        self.course_fixture.install()

        self.enable_forums()

    def create_single_thread_page(self, thread_id):
        """
        Sets up a `DiscussionTabSingleThreadPage` for a given
        `thread_id`.
        """
        return DiscussionTabSingleThreadPage(self.browser, self.course_id, self.discussion_id, thread_id)
コード例 #8
0
ファイル: helpers.py プロジェクト: luisvasq/edx-platform
class BaseDiscussionTestCase(UniqueCourseTest, ForumsConfigMixin):
    """Base test case class for all discussions-related tests."""
    def setUp(self):
        super(BaseDiscussionTestCase, self).setUp()

        self.discussion_id = "test_discussion_{}".format(uuid4().hex)
        self.course_fixture = CourseFixture(**self.course_info)
        self.course_fixture.add_children(
            XBlockFixtureDesc("chapter", "Test Section").add_children(
                XBlockFixtureDesc("sequential", "Test Subsection").add_children(
                    XBlockFixtureDesc("vertical", "Test Unit").add_children(
                        XBlockFixtureDesc(
                            "discussion",
                            "Test Discussion",
                            metadata={"discussion_id": self.discussion_id}
                        )
                    )
                )
            )
        )
        self.course_fixture.add_advanced_settings(
            {'discussion_topics': {'value': {'General': {'id': 'course'}}}}
        )
        self.course_fixture.install()

        self.enable_forums()

    def create_single_thread_page(self, thread_id):
        """
        Sets up a `DiscussionTabSingleThreadPage` for a given
        `thread_id`.
        """
        return DiscussionTabSingleThreadPage(self.browser, self.course_id, self.discussion_id, thread_id)
コード例 #9
0
class CreateCCXCoachTest(EventsTestMixin, UniqueCourseTest):
    """
    Test ccx end to end process.
    """
    USERNAME = "******"
    EMAIL = "*****@*****.**"
    shard = 7

    def setUp(self):
        super(CreateCCXCoachTest, self).setUp()
        self.course_info.update({"settings": {"enable_ccx": "true"}})
        self.course_fixture = CourseFixture(**self.course_info)
        self.course_fixture.add_advanced_settings(
            {"enable_ccx": {
                "value": "true"
            }})
        self.course_fixture.install()

        self.auto_auth(self.USERNAME, self.EMAIL)
        self.coach_dashboard_page = self.visit_coach_dashboard()

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

    def visit_coach_dashboard(self):
        """
        Visits the instructor dashboard.
        """
        coach_dashboard_page = CoachDashboardPage(self.browser, self.course_id)
        coach_dashboard_page.visit()
        return coach_dashboard_page

    def test_create_ccx(self):
        """
        Assert that ccx created.
        """
        ccx_name = "Test ccx"

        self.coach_dashboard_page.fill_ccx_name_text_box(ccx_name)
        self.coach_dashboard_page.wait_for_page()

        # Assert that new ccx is created and we are on ccx dashboard/enrollment tab.
        self.assertTrue(
            self.coach_dashboard_page.is_browser_on_enrollment_page())

        # Assert that the user cannot click in the "View Unit in Studio" button,
        # which means the user cannot edit the ccx course in studio
        self.assertFalse(
            self.coach_dashboard_page.is_button_view_unit_in_studio_visible())
コード例 #10
0
ファイル: test_ccx.py プロジェクト: cmscom/edx-platform
class CreateCCXCoachTest(EventsTestMixin, UniqueCourseTest):
    """
    Test ccx end to end process.
    """
    USERNAME = "******"
    EMAIL = "*****@*****.**"
    shard = 7

    def setUp(self):
        super(CreateCCXCoachTest, self).setUp()
        self.course_info.update({"settings": {"enable_ccx": "true"}})
        self.course_fixture = CourseFixture(**self.course_info)
        self.course_fixture.add_advanced_settings({
            "enable_ccx": {"value": "true"}
        })
        self.course_fixture.install()

        self.auto_auth(self.USERNAME, self.EMAIL)
        self.coach_dashboard_page = self.visit_coach_dashboard()

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

    def visit_coach_dashboard(self):
        """
        Visits the instructor dashboard.
        """
        coach_dashboard_page = CoachDashboardPage(self.browser, self.course_id)
        coach_dashboard_page.visit()
        return coach_dashboard_page

    def test_create_ccx(self):
        """
        Assert that ccx created.
        """
        ccx_name = "Test ccx"

        self.coach_dashboard_page.fill_ccx_name_text_box(ccx_name)
        self.coach_dashboard_page.wait_for_page()

        # Assert that new ccx is created and we are on ccx dashboard/enrollment tab.
        self.assertTrue(self.coach_dashboard_page.is_browser_on_enrollment_page())

        # Assert that the user cannot click in the "View Unit in Studio" button,
        # which means the user cannot edit the ccx course in studio
        self.assertFalse(self.coach_dashboard_page.is_button_view_unit_in_studio_visible())
コード例 #11
0
ファイル: helpers.py プロジェクト: CraftAcademy/edx-platform
class BaseDiscussionTestCase(UniqueCourseTest):
    def setUp(self):
        super(BaseDiscussionTestCase, self).setUp()

        self.discussion_id = "test_discussion_{}".format(uuid4().hex)
        self.course_fixture = CourseFixture(**self.course_info)
        self.course_fixture.add_advanced_settings(
            {'discussion_topics': {'value': {'Test Discussion Topic': {'id': self.discussion_id}}}}
        )
        self.course_fixture.install()

    def create_single_thread_page(self, thread_id):
        """
        Sets up a `DiscussionTabSingleThreadPage` for a given
        `thread_id`.
        """
        return DiscussionTabSingleThreadPage(self.browser, self.course_id, self.discussion_id, thread_id)
コード例 #12
0
class BaseLmsDashboardTest(UniqueCourseTest):
    """ Base test suite for the LMS Student Dashboard """

    def setUp(self):
        """
        Initializes the components (page objects, courses, users) for this test suite
        """
        # Some parameters are provided by the parent setUp() routine, such as the following:
        # self.course_id, self.course_info, self.unique_id
        super(BaseLmsDashboardTest, self).setUp()

        # Load page objects for use by the tests
        self.dashboard_page = DashboardPage(self.browser)

        # Configure some aspects of the test course and install the settings into the course
        self.course_fixture = CourseFixture(
            self.course_info["org"],
            self.course_info["number"],
            self.course_info["run"],
            self.course_info["display_name"],
        )
        self.course_fixture.add_advanced_settings({
            u"social_sharing_url": {u"value": "http://custom/course/url"}
        })
        self.course_fixture.install()

        self.username = "******".format(uuid=self.unique_id[0:6])
        self.email = "{user}@example.com".format(user=self.username)

        # Create the test user, register them for the course, and authenticate
        AutoAuthPage(
            self.browser,
            username=self.username,
            email=self.email,
            course_id=self.course_id
        ).visit()

        # Navigate the authenticated, enrolled user to the dashboard page and get testing!
        self.dashboard_page.visit()
コード例 #13
0
class BaseLmsDashboardTest(UniqueCourseTest):
    """ Base test suite for the LMS Student Dashboard """

    def setUp(self):
        """
        Initializes the components (page objects, courses, users) for this test suite
        """
        # Some parameters are provided by the parent setUp() routine, such as the following:
        # self.course_id, self.course_info, self.unique_id
        super(BaseLmsDashboardTest, self).setUp()

        # Load page objects for use by the tests
        self.dashboard_page = DashboardPage(self.browser)

        # Configure some aspects of the test course and install the settings into the course
        self.course_fixture = CourseFixture(
            self.course_info["org"],
            self.course_info["number"],
            self.course_info["run"],
            self.course_info["display_name"],
        )
        self.course_fixture.add_advanced_settings({
            u"social_sharing_url": {u"value": "http://custom/course/url"}
        })
        self.course_fixture.install()

        self.username = "******".format(uuid=self.unique_id[0:6])
        self.email = "{user}@example.com".format(user=self.username)

        # Create the test user, register them for the course, and authenticate
        AutoAuthPage(
            self.browser,
            username=self.username,
            email=self.email,
            course_id=self.course_id
        ).visit()

        # Navigate the authenticated, enrolled user to the dashboard page and get testing!
        self.dashboard_page.visit()
コード例 #14
0
ファイル: test_lms.py プロジェクト: cmscom/edx-platform
    def setUp(self):
        """
        Initialize pages and install a course fixture.
        """
        super(PDFTextBooksTabTest, self).setUp()

        self.course_home_page = CourseHomePage(self.browser, self.course_id)
        self.tab_nav = TabNavPage(self.browser)

        # Install a course with TextBooks
        course_fix = CourseFixture(
            self.course_info['org'], self.course_info['number'],
            self.course_info['run'], self.course_info['display_name']
        )

        # Add PDF textbooks to course fixture.
        for i in range(1, 3):
            course_fix.add_textbook("PDF Book {}".format(i), [{"title": "Chapter Of Book {}".format(i), "url": ""}])

        course_fix.install()

        # Auto-auth register for the course
        AutoAuthPage(self.browser, course_id=self.course_id).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"
            },
            "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.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 there 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_home_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_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()
コード例 #16
0
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()
コード例 #17
0
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.course_nav = CourseNavPage(self.browser)
        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")

        # Navigate to Test Subsection in Test Section Section
        self.course_nav.go_to_section("Test Section", "Test Subsection")

        # Navigate to Test Problem 1
        self.course_nav.go_to_vertical("Test Problem 1")

        # Select correct value for from select menu
        self.course_nav.q(css='select option[value="{}"]'.format("blue")).first.click()

        # Select correct radio button for the answer
        self.course_nav.q(css="fieldset div.field:nth-child(3) input").nth(0).click()

        # Select correct radio buttons for the answer
        self.course_nav.q(css="fieldset div.field:nth-child(1) input").nth(1).click()
        self.course_nav.q(css="fieldset div.field:nth-child(3) input").nth(1).click()

        # Submit the answer
        self.course_nav.q(css="button.check.Check").click()
        self.course_nav.wait_for_ajax()

        # Navigate to the 'Test Subsection 2' of 'Test Section 2'
        self.course_nav.go_to_section("Test Section 2", "Test Subsection 2")

        # Navigate to Test Problem 2
        self.course_nav.go_to_vertical("Test Problem 2")

        # Fill in the answer of the problem
        self.course_nav.q(css="input[id^=input_][id$=_2_1]").fill("A*x^2 + sqrt(y)")

        # Submit the answer
        self.course_nav.q(css="button.check.Check").click()
        self.course_nav.wait_for_ajax()
コード例 #18
0
class SignUpAndSignInTest(UniqueCourseTest):
    """
    Test studio sign-up and sign-in
    """
    shard = 21

    def setUp(self):
        super(SignUpAndSignInTest, self).setUp()
        self.sign_up_page = SignupPage(self.browser)
        self.login_page = LoginPage(self.browser)

        self.course_outline_page = CourseOutlinePage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])
        self.course_outline_sign_in_redirect_page = CourseOutlineSignInRedirectPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name'],
        )
        self.user = None

    def install_course_fixture(self):
        """
        Install a course fixture
        """
        self.course_fixture.install()
        self.user = self.course_fixture.user

    def test_sign_up_from_home(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        And I press the Create My Account button on the registration form
        Then I should see an email verification prompt
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        # Register the user.
        unique_number = uuid.uuid4().hex[:4]
        self.sign_up_page.sign_up_user(
            '{}[email protected]'.format(unique_number),
            '{}-name'.format(unique_number),
            '{}-username'.format(unique_number),
            '{}-password'.format(unique_number),
        )
        home = HomePage(self.browser)
        home.wait_for_page()

    def test_sign_up_with_bad_password(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        When I enter an insufficient password and focus out
        I should see an error message
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        password_input = self.sign_up_page.input_password(
            'a')  # Arbitrary short password that will fail
        password_input.send_keys(Keys.TAB)  # Focus out of the element
        index_page.wait_for_element_visibility(
            '#register-password-validation-error', 'Password Error Message')
        self.assertIsNotNone(
            index_page.q(css='#register-password-validation-error-msg')
        )  # Error message should exist

    def test_login_with_valid_redirect(self):
        """
        Scenario: Login with a valid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/course/slashes:MITx+999+Robot_Super_Course"
        And I should see the path is "/signin_redirect_to_lms?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
        When I fill in and submit the LMS login form
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        # Get the url, browser should land here after sign in.
        course_url = self.course_outline_sign_in_redirect_page.url
        self.course_outline_sign_in_redirect_page.visit()
        # Login
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, course_url)
コード例 #19
0
class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest, TestWithSearchIndexMixin):
    """
    Test Library Content block in LMS
    """
    shard = 17

    def setUp(self):
        """
        Install library with some content and a course using fixtures
        """
        self._create_search_index()
        super(StudioLibraryContainerTest, self).setUp()
        # Also create a course:
        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)
        self.course_fixture.install()
        self.outline = CourseOutlinePage(
            self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
        )

        self.outline.visit()
        subsection = self.outline.section(SECTION_NAME).subsection(SUBSECTION_NAME)
        self.unit_page = subsection.expand_subsection().unit(UNIT_NAME).go_to()

    def tearDown(self):
        """ Tear down method: remove search index backing file """
        self._cleanup_index_file()
        super(StudioLibraryContainerTest, self).tearDown()

    def populate_library_fixture(self, library_fixture):
        """
        Populate the children of the test course fixture.
        """
        library_fixture.add_children(
            XBlockFixtureDesc("html", "Html1"),
            XBlockFixtureDesc("html", "Html2"),
            XBlockFixtureDesc("html", "Html3"),
        )

    def populate_course_fixture(self, course_fixture):
        """ Install a course with sections/problems, tabs, updates, and handouts """
        library_content_metadata = {
            'source_library_id': six.text_type(self.library_key),
            'mode': 'random',
            'max_count': 1,
        }

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', SECTION_NAME).add_children(
                XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children(
                    XBlockFixtureDesc('vertical', UNIT_NAME).add_children(
                        XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata)
                    )
                )
            )
        )

    def _get_library_xblock_wrapper(self, xblock):
        """
        Wraps xblock into :class:`...pages.studio.library.StudioLibraryContainerXBlockWrapper`
        """
        return StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(xblock)

    @ddt.data(1, 2, 3)
    def test_can_edit_metadata(self, max_count):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I edit library content metadata and save it
        Then I can ensure that data is persisted
        """
        library_name = self.library_info['display_name']
        library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])
        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        edit_modal.library_name = library_name
        edit_modal.count = max_count

        library_container.save_settings()  # saving settings

        # open edit window again to verify changes are persistent
        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        self.assertEqual(edit_modal.library_name, library_name)
        self.assertEqual(edit_modal.count, max_count)

    def test_no_content_message(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I set Problem Type selector so that no libraries have matching content
        Then I can see that "No matching content" warning is shown
        When I set Problem Type selector so that there is matching content
        Then I can see that warning messages are not shown
        """
        # Add a single "Dropdown" type problem to the library (which otherwise has only HTML blocks):
        self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc(
            "problem", "Dropdown",
            data=textwrap.dedent("""
                <problem>
                    <p>Dropdown</p>
                    <optionresponse><optioninput label="Dropdown" options="('1', '2')" correct="'2'"></optioninput></optionresponse>
                </problem>
                """)
        ))

        expected_text = 'There are no matching problem types in the specified libraries. Select another problem type'

        library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])

        # precondition check - assert library has children matching filter criteria
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        self.assertEqual(edit_modal.capa_type, "Any Type")  # precondition check
        edit_modal.capa_type = "Custom Evaluated Script"

        library_container.save_settings()

        self.assertTrue(library_container.has_validation_warning)
        self.assertIn(expected_text, library_container.validation_warning_text)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        self.assertEqual(edit_modal.capa_type, "Custom Evaluated Script")  # precondition check
        edit_modal.capa_type = "Dropdown"
        library_container.save_settings()

        # Library should contain single Dropdown problem, so now there should be no errors again
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

    def test_cannot_manage(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And when I click the "View" link
        Then I can see a preview of the blocks drawn from the library.

        And I do not see a duplicate button
        And I do not see a delete button
        """
        block_wrapper_unit_page = self._get_library_xblock_wrapper(self.unit_page.xblocks[0].children[0])
        container_page = block_wrapper_unit_page.go_to_container()

        for block in container_page.xblocks:
            self.assertFalse(block.has_duplicate_button)
            self.assertFalse(block.has_delete_button)
            self.assertFalse(block.has_edit_visibility_button)
コード例 #20
0
    def setUp(self):
        """
        Initializes the components (page objects, courses, users) for this test suite
        """
        # Some parameters are provided by the parent setUp() routine, such as the following:
        # self.course_id, self.course_info, self.unique_id
        super(BaseLmsDashboardTestMultiple, self).setUp()

        # Load page objects for use by the tests
        self.dashboard_page = DashboardPage(self.browser)

        # Configure some aspects of the test course and install the settings into the course
        self.courses = {
            'A': {
                'org': 'test_org',
                'number': self.unique_id,
                'run': 'test_run_A',
                'display_name': 'Test Course A',
                'enrollment_mode': 'audit',
                'cert_name_long': 'Certificate of Audit Achievement'
            },
            'B': {
                'org': 'test_org',
                'number': self.unique_id,
                'run': 'test_run_B',
                'display_name': 'Test Course B',
                'enrollment_mode': 'verified',
                'cert_name_long': 'Certificate of Verified Achievement'
            },
            'C': {
                'org': 'test_org',
                'number': self.unique_id,
                'run': 'test_run_C',
                'display_name': 'Test Course C',
                'enrollment_mode': 'credit',
                'cert_name_long': 'Certificate of Credit Achievement'
            }
        }

        self.username = "******".format(uuid=self.unique_id[0:6])
        self.email = "{user}@example.com".format(user=self.username)

        self.course_keys = {}
        self.course_fixtures = {}

        for key, value in self.courses.iteritems():
            course_key = generate_course_key(
                value['org'],
                value['number'],
                value['run'],
            )

            course_fixture = CourseFixture(
                value['org'],
                value['number'],
                value['run'],
                value['display_name'],
            )

            course_fixture.add_advanced_settings({
                u"social_sharing_url": {u"value": "http://custom/course/url"},
                u"cert_name_long": {u"value": value['cert_name_long']}
            })

            course_fixture.install()

            self.course_keys[key] = course_key
            self.course_fixtures[key] = course_fixture

            # Create the test user, register them for the course, and authenticate
            AutoAuthPage(
                self.browser,
                username=self.username,
                email=self.email,
                course_id=course_key,
                enrollment_mode=value['enrollment_mode']
            ).visit()

        # Navigate the authenticated, enrolled user to the dashboard page and get testing!
        self.dashboard_page.visit()
コード例 #21
0
class SignUpAndSignInTest(UniqueCourseTest):
    """
    Test studio sign-up and sign-in
    """
    shard = 21

    def setUp(self):  # pylint: disable=arguments-differ
        super(SignUpAndSignInTest, self).setUp()
        self.sign_up_page = SignupPage(self.browser)
        self.login_page = LoginPage(self.browser)

        self.course_outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        self.course_outline_sign_in_redirect_page = CourseOutlineSignInRedirectPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name'],
        )
        self.user = None

    def install_course_fixture(self):
        """
        Install a course fixture
        """
        self.course_fixture.install()
        self.user = self.course_fixture.user

    def test_sign_up_from_home(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        And I press the Create My Account button on the registration form
        Then I should see an email verification prompt
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        unique_number = uuid.uuid4().hex[:4]
        registration_dic = {
            '#email': '{}[email protected]'.format(unique_number),
            '#name': '{}-name'.format(unique_number),
            '#username': '******'.format(unique_number),
            '#password': '******'.format(unique_number),
        }
        # Register the user.
        self.sign_up_page.sign_up_user(registration_dic)
        home = HomePage(self.browser)
        home.wait_for_page()

    def test_sign_up_with_bad_password(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        When I enter an insufficient password and focus out
        I should see an error message
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        password_input = self.sign_up_page.input_password('a')  # Arbitrary short password that will fail
        password_input.send_keys(Keys.TAB)  # Focus out of the element
        index_page.wait_for_element_visibility('#password_error', 'Password Error Message')
        self.assertIsNotNone(index_page.q(css='#password_error').text)  # Make sure there is an error message

    def test_login_with_valid_redirect(self):
        """
        Scenario: Login with a valid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/course/slashes:MITx+999+Robot_Super_Course"
        And I should see that the path is "/signin?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
        When I fill in and submit the signin form
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        # Get the url, browser should land here after sign in.
        course_url = self.course_outline_sign_in_redirect_page.url
        self.course_outline_sign_in_redirect_page.visit()
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, course_url)

    def test_login_with_invalid_redirect(self):
        """
        Scenario: Login with an invalid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/signin?next=http://www.google.com/"
        When I fill in and submit the signin form
        Then I should see that the path is "/home/"
        """
        self.install_course_fixture()
        # Visit course
        self.course_outline_sign_in_redirect_page.visit()
        # Change redirect url
        self.browser.get(self.browser.current_url.split('=')[0] + '=http://www.google.com')
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        home = HomePage(self.browser)
        home.wait_for_page()
        self.assertEqual(self.browser.current_url, home.url)

    def test_login_with_mistyped_credentials(self):
        """
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the Studio homepage
        When I click the link with the text "Sign In"
        Then I should see that the path is "/signin"
        And I should not see a login error message
        And I fill in and submit the signin form incorrectly
        Then I should see a login error message
        And I edit the password field
        Then I should not see a login error message
        And I submit the signin form
        And I wait for "2" seconds
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        self.course_outline_sign_in_redirect_page.visit()
        # Verify login_error is not present
        self.course_outline_sign_in_redirect_page.wait_for_element_absence(
            '#login_error',
            'Login error not be present'
        )
        # Login with wrong credentials
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'],
            'wrong_password',
            expect_success=False
        )
        # Verify that login error is shown
        self.course_outline_sign_in_redirect_page.wait_for_element_visibility(
            '#login_error',
            'Login error is visible'
        )
        # Change the password
        self.course_outline_sign_in_redirect_page.fill_field('input#password', 'changed_password')
        # Login error should not be visible
        self.course_outline_sign_in_redirect_page.wait_for_element_invisibility(
            '#login_error',
            'Login error is not visible'
        )
        # Login with correct credentials
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, self.course_outline_page.url)
コード例 #22
0
class SignUpAndSignInTest(UniqueCourseTest):
    """
    Test studio sign-up and sign-in
    """
    shard = 21

    def setUp(self):
        super(SignUpAndSignInTest, self).setUp()
        self.sign_up_page = SignupPage(self.browser)
        self.login_page = LoginPage(self.browser)

        self.course_outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        self.course_outline_sign_in_redirect_page = CourseOutlineSignInRedirectPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name'],
        )
        self.user = None

    def install_course_fixture(self):
        """
        Install a course fixture
        """
        self.course_fixture.install()
        self.user = self.course_fixture.user

    def test_sign_up_from_home(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        And I press the Create My Account button on the registration form
        Then I should see an email verification prompt
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        # Register the user.
        unique_number = uuid.uuid4().hex[:4]
        self.sign_up_page.sign_up_user(
            '{}[email protected]'.format(unique_number),
            '{}-name'.format(unique_number),
            '{}-username'.format(unique_number),
            '{}-password'.format(unique_number),
        )
        home = HomePage(self.browser)
        home.wait_for_page()

    def test_sign_up_with_bad_password(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        When I enter an insufficient password and focus out
        I should see an error message
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        password_input = self.sign_up_page.input_password('a')  # Arbitrary short password that will fail
        password_input.send_keys(Keys.TAB)  # Focus out of the element
        index_page.wait_for_element_visibility('#register-password-validation-error', 'Password Error Message')
        self.assertIsNotNone(index_page.q(css='#register-password-validation-error-msg'))  # Error message should exist

    def test_login_with_valid_redirect(self):
        """
        Scenario: Login with a valid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/course/slashes:MITx+999+Robot_Super_Course"
        And I should see that the path is "/signin?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
        When I fill in and submit the signin form
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        # Get the url, browser should land here after sign in.
        course_url = self.course_outline_sign_in_redirect_page.url
        self.course_outline_sign_in_redirect_page.visit()
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, course_url)

    def test_login_with_invalid_redirect(self):
        """
        Scenario: Login with an invalid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/signin?next=http://www.google.com/"
        When I fill in and submit the signin form
        Then I should see that the path is "/home/"
        """
        self.install_course_fixture()
        # Visit course
        self.course_outline_sign_in_redirect_page.visit()
        # Change redirect url
        self.browser.get(self.browser.current_url.split('=')[0] + '=http://www.google.com')
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        # Verify that we land in LMS instead of the invalid redirect url
        self.assertEqual(self.browser.current_url, LMS_URL + "/dashboard")

    def test_login_with_mistyped_credentials(self):
        """
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the Studio homepage
        When I click the link with the text "Sign In"
        Then I should see that the path is "/signin"
        And I should not see a login error message
        And I fill in and submit the signin form incorrectly
        Then I should see a login error message
        And I edit the password field
        Then I should not see a login error message
        And I submit the signin form
        And I wait for "2" seconds
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        self.course_outline_sign_in_redirect_page.visit()
        # Verify login_error is not present
        self.course_outline_sign_in_redirect_page.wait_for_element_absence(
            '#login_error',
            'Login error not be present'
        )
        # Login with wrong credentials
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'],
            'wrong_password',
            expect_success=False
        )
        # Verify that login error is shown
        self.course_outline_sign_in_redirect_page.wait_for_element_visibility(
            ".js-form-errors.status.submission-error",
            'Login error is visible'
        )
        # Login with correct credentials
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, self.course_outline_page.url)
コード例 #23
0
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"},
            "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.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 there 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_home_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_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()
コード例 #24
0
class StudioCourseTest(UniqueCourseTest):
    """
    Base class for all Studio course tests.
    """

    def setUp(self, is_staff=False, test_xss=True):  # pylint: disable=arguments-differ
        """
        Install a course with no content using a fixture.
        """
        super(StudioCourseTest, self).setUp()
        self.test_xss = test_xss
        self.install_course_fixture(is_staff)

    def install_course_fixture(self, is_staff=False):
        """
        Install a course fixture
        """
        self.course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name'],
        )
        if self.test_xss:
            xss_injected_unique_id = XSS_INJECTION + self.unique_id
            test_improper_escaping = {u"value": xss_injected_unique_id}
            self.course_fixture.add_advanced_settings({
                "advertised_start": test_improper_escaping,
                "info_sidebar_name": test_improper_escaping,
                "cert_name_short": test_improper_escaping,
                "cert_name_long": test_improper_escaping,
                "display_organization": test_improper_escaping,
                "display_coursenumber": test_improper_escaping,
            })
            self.course_info['display_organization'] = xss_injected_unique_id
            self.course_info['display_coursenumber'] = xss_injected_unique_id
        self.populate_course_fixture(self.course_fixture)
        self.course_fixture.install()
        self.user = self.course_fixture.user
        self.log_in(self.user, is_staff)

    def populate_course_fixture(self, course_fixture):
        """
        Populate the children of the test course fixture.
        """
        pass

    def log_in(self, user, is_staff=False):
        """
        Log in as the user that created the course. The user will be given instructor access
        to the course and enrolled in it. By default the user will not have staff access unless
        is_staff is passed as True.

        Args:
            user(dict): dictionary containing user data: {'username': ..., 'email': ..., 'password': ...}
            is_staff(bool): register this user as staff
        """
        self.auth_page = AutoAuthPage(
            self.browser,
            staff=is_staff,
            username=user.get('username'),
            email=user.get('email'),
            password=user.get('password')
        )
        self.auth_page.visit()
コード例 #25
0
class CertificateWebViewTest(EventsTestMixin, UniqueCourseTest):
    """
    Tests for verifying certificate web view features
    """
    shard = 5

    def setUp(self):
        super(CertificateWebViewTest, self).setUp()
        # set same course number as we have in fixture json
        self.course_info['number'] = "335535897951379478207964576572017930000"
        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_display_behavior": {"value": "early_with_info"},
        })
        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)

        # Load certificate web view page for use by the tests
        self.certificate_page = CertificatePage(self.browser, self.user_id, self.course_id)

    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_page_has_accomplishments_banner(self):
        """
        Scenario: User accomplishment banner should be present if logged in user is the one who is awarded
         the certificate
        Given there is a course with certificate configuration
        And I have passed the course and certificate is generated
        When I view the certificate web view page
        Then I should see the accomplishment banner. banner should have linked-in and facebook share buttons
        And When I click on `Add to Profile` button `edx.certificate.shared` event should be emitted
        """
        self.cert_fixture.install()
        self.log_in_as_unique_user()
        self.certificate_page.visit()
        self.assertTrue(self.certificate_page.accomplishment_banner.visible)
        self.assertTrue(self.certificate_page.add_to_linkedin_profile_button.visible)
        self.assertTrue(self.certificate_page.add_to_facebook_profile_button.visible)
        self.certificate_page.add_to_linkedin_profile_button.click()
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.certificate.shared'},
            number_of_matches=1
        )
        expected_events = [
            {
                'event': {
                    'user_id': self.user_id,
                    'course_id': self.course_id
                }
            }
        ]
        self.assert_events_match(expected_events, actual_events)
コード例 #26
0
class SignUpAndSignInTest(UniqueCourseTest):
    """
    Test studio sign-up and sign-in
    """

    def setUp(self):  # pylint: disable=arguments-differ
        super(SignUpAndSignInTest, self).setUp()
        self.sign_up_page = SignupPage(self.browser)
        self.login_page = LoginPage(self.browser)

        self.course_outline_page = CourseOutlinePage(
            self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"]
        )
        self.course_outline_sign_in_redirect_page = CourseOutlineSignInRedirectPage(
            self.browser, self.course_info["org"], self.course_info["number"], self.course_info["run"]
        )

        self.course_fixture = CourseFixture(
            self.course_info["org"],
            self.course_info["number"],
            self.course_info["run"],
            self.course_info["display_name"],
        )
        self.user = None

    def install_course_fixture(self):
        """
        Install a course fixture
        """
        self.course_fixture.install()
        self.user = self.course_fixture.user

    def test_sign_up_from_home(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        And I press the Create My Account button on the registration form
        Then I should see an email verification prompt
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        unique_number = uuid.uuid4().hex[:4]
        registration_dic = {
            "#email": "{}[email protected]".format(unique_number),
            "#name": "{}-name".format(unique_number),
            "#username": "******".format(unique_number),
            "#password": "******".format(unique_number),
        }
        # Register the user.
        self.sign_up_page.sign_up_user(registration_dic)
        home = HomePage(self.browser)
        home.wait_for_page()

    def test_login_with_valid_redirect(self):
        """
        Scenario: Login with a valid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/course/slashes:MITx+999+Robot_Super_Course"
        And I should see that the path is "/signin?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
        When I fill in and submit the signin form
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        # Get the url, browser should land here after sign in.
        course_url = self.course_outline_sign_in_redirect_page.url
        self.course_outline_sign_in_redirect_page.visit()
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user["email"], self.user["password"])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, course_url)

    def test_login_with_invalid_redirect(self):
        """
        Scenario: Login with an invalid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/signin?next=http://www.google.com/"
        When I fill in and submit the signin form
        Then I should see that the path is "/home/"
        """
        self.install_course_fixture()
        # Visit course
        self.course_outline_sign_in_redirect_page.visit()
        # Change redirect url
        self.browser.get(self.browser.current_url.split("=")[0] + "=http://www.google.com")
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user["email"], self.user["password"])
        home = HomePage(self.browser)
        home.wait_for_page()
        self.assertEqual(self.browser.current_url, home.url)

    def test_login_with_mistyped_credentials(self):
        """
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the Studio homepage
        When I click the link with the text "Sign In"
        Then I should see that the path is "/signin"
        And I should not see a login error message
        And I fill in and submit the signin form incorrectly
        Then I should see a login error message
        And I edit the password field
        Then I should not see a login error message
        And I submit the signin form
        And I wait for "2" seconds
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        self.course_outline_sign_in_redirect_page.visit()
        # Verify login_error is not present
        self.course_outline_sign_in_redirect_page.wait_for_element_absence("#login_error", "Login error not be present")
        # Login with wrong credentials
        self.course_outline_sign_in_redirect_page.login(self.user["email"], "wrong_password", expect_success=False)
        # Verify that login error is shown
        self.course_outline_sign_in_redirect_page.wait_for_element_visibility("#login_error", "Login error is visible")
        # Change the password
        self.course_outline_sign_in_redirect_page.fill_field("input#password", "changed_password")
        # Login error should not be visible
        self.course_outline_sign_in_redirect_page.wait_for_element_invisibility(
            "#login_error", "Login error is not visible"
        )
        # Login with correct credentials
        self.course_outline_sign_in_redirect_page.login(self.user["email"], self.user["password"])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, self.course_outline_page.url)
コード例 #27
0
class CertificateWebViewTest(EventsTestMixin, UniqueCourseTest):
    """
    Tests for verifying certificate web view features
    """
    shard = 5

    def setUp(self):
        super(CertificateWebViewTest, self).setUp()
        # set same course number as we have in fixture json
        self.course_info['number'] = "335535897951379478207964576572017930000"
        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_display_behavior": {"value": "early_with_info"},
        })
        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)

        # Load certificate web view page for use by the tests
        self.certificate_page = CertificatePage(self.browser, self.user_id, self.course_id)

    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_page_has_accomplishments_banner(self):
        """
        Scenario: User accomplishment banner should be present if logged in user is the one who is awarded
         the certificate
        Given there is a course with certificate configuration
        And I have passed the course and certificate is generated
        When I view the certificate web view page
        Then I should see the accomplishment banner. banner should have linked-in and facebook share buttons
        And When I click on `Add to Profile` button `edx.certificate.shared` event should be emitted
        """
        self.cert_fixture.install()
        self.log_in_as_unique_user()
        self.certificate_page.visit()
        self.assertTrue(self.certificate_page.accomplishment_banner.visible)
        self.assertTrue(self.certificate_page.add_to_linkedin_profile_button.visible)
        self.assertTrue(self.certificate_page.add_to_facebook_profile_button.visible)
        self.certificate_page.add_to_linkedin_profile_button.click()
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.certificate.shared'},
            number_of_matches=1
        )
        expected_events = [
            {
                'event': {
                    'user_id': self.user_id,
                    'course_id': self.course_id
                }
            }
        ]
        self.assert_events_match(expected_events, actual_events)
コード例 #28
0
class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest,
                                 TestWithSearchIndexMixin):
    """
    Test Library Content block in LMS
    """
    def setUp(self):
        """
        Install library with some content and a course using fixtures
        """
        self._create_search_index()
        super(StudioLibraryContainerTest, self).setUp()
        # Also create a course:
        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)
        self.course_fixture.install()
        self.outline = CourseOutlinePage(self.browser, self.course_info['org'],
                                         self.course_info['number'],
                                         self.course_info['run'])

        self.outline.visit()
        subsection = self.outline.section(SECTION_NAME).subsection(
            SUBSECTION_NAME)
        self.unit_page = subsection.expand_subsection().unit(UNIT_NAME).go_to()

    def tearDown(self):
        """ Tear down method: remove search index backing file """
        self._cleanup_index_file()
        super(StudioLibraryContainerTest, self).tearDown()

    def populate_library_fixture(self, library_fixture):
        """
        Populate the children of the test course fixture.
        """
        library_fixture.add_children(
            XBlockFixtureDesc("html", "Html1"),
            XBlockFixtureDesc("html", "Html2"),
            XBlockFixtureDesc("html", "Html3"),
        )

    def populate_course_fixture(self, course_fixture):
        """ Install a course with sections/problems, tabs, updates, and handouts """
        library_content_metadata = {
            'source_library_id': unicode(self.library_key),
            'mode': 'random',
            'max_count': 1,
            'has_score': False
        }

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', SECTION_NAME).add_children(
                XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children(
                    XBlockFixtureDesc('vertical', UNIT_NAME).add_children(
                        XBlockFixtureDesc(
                            'library_content',
                            "Library Content",
                            metadata=library_content_metadata)))))

    def _get_library_xblock_wrapper(self, xblock):
        """
        Wraps xblock into :class:`...pages.studio.library.StudioLibraryContainerXBlockWrapper`
        """
        return StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(xblock)

    @ddt.data(
        (1, True),
        (2, False),
        (3, True),
    )
    @ddt.unpack
    def test_can_edit_metadata(self, max_count, scored):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I edit library content metadata and save it
        Then I can ensure that data is persisted
        """
        library_name = self.library_info['display_name']
        library_container = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[1])
        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser,
                                                library_container.locator)
        edit_modal.library_name = library_name
        edit_modal.count = max_count
        edit_modal.scored = scored

        library_container.save_settings()  # saving settings

        # open edit window again to verify changes are persistent
        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser,
                                                library_container.locator)
        self.assertEqual(edit_modal.library_name, library_name)
        self.assertEqual(edit_modal.count, max_count)
        self.assertEqual(edit_modal.scored, scored)

    def test_no_library_shows_library_not_configured(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I edit to select "No Library"
        Then I can see that library content block is misconfigured
        """
        expected_text = 'A library has not yet been selected.'
        expected_action = 'Select a Library'
        library_container = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[1])

        # precondition check - the library block should be configured before we remove the library setting
        self.assertFalse(
            library_container.has_validation_not_configured_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser,
                                                library_container.locator)
        edit_modal.library_name = "No Library Selected"
        library_container.save_settings()

        self.assertTrue(
            library_container.has_validation_not_configured_warning)
        self.assertIn(expected_text,
                      library_container.validation_not_configured_warning_text)
        self.assertIn(expected_action,
                      library_container.validation_not_configured_warning_text)

    def test_out_of_date_message(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        Then I update the library being used
        Then I refresh the page
        Then I can see that library content block needs to be updated
        When I click on the update link
        Then I can see that the content no longer needs to be updated
        """
        # Formerly flaky: see TE-745
        expected_text = "This component is out of date. The library has new content."
        library_block = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[1])

        self.assertFalse(library_block.has_validation_warning)
        # Removed this assert until a summary message is added back to the author view (SOL-192)
        #self.assertIn("3 matching components", library_block.author_content)

        self.library_fixture.create_xblock(
            self.library_fixture.library_location,
            XBlockFixtureDesc("html", "Html4"))

        self.unit_page.visit()  # Reload the page

        self.assertTrue(library_block.has_validation_warning)
        self.assertIn(expected_text, library_block.validation_warning_text)

        library_block.refresh_children()

        self.unit_page.wait_for_page()  # Wait for the page to reload
        library_block = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[1])

        self.assertFalse(library_block.has_validation_message)
        # Removed this assert until a summary message is added back to the author view (SOL-192)
        #self.assertIn("4 matching components", library_block.author_content)

    def test_no_content_message(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I set Problem Type selector so that no libraries have matching content
        Then I can see that "No matching content" warning is shown
        When I set Problem Type selector so that there is matching content
        Then I can see that warning messages are not shown
        """
        # Add a single "Dropdown" type problem to the library (which otherwise has only HTML blocks):
        self.library_fixture.create_xblock(
            self.library_fixture.library_location,
            XBlockFixtureDesc("problem",
                              "Dropdown",
                              data=textwrap.dedent("""
                <problem>
                    <p>Dropdown</p>
                    <optionresponse><optioninput label="Dropdown" options="('1', '2')" correct="'2'"></optioninput></optionresponse>
                </problem>
                """)))

        expected_text = 'There are no matching problem types in the specified libraries. Select another problem type'

        library_container = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[1])

        # precondition check - assert library has children matching filter criteria
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser,
                                                library_container.locator)
        self.assertEqual(edit_modal.capa_type,
                         "Any Type")  # precondition check
        edit_modal.capa_type = "Custom Evaluated Script"

        library_container.save_settings()

        self.assertTrue(library_container.has_validation_warning)
        self.assertIn(expected_text, library_container.validation_warning_text)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser,
                                                library_container.locator)
        self.assertEqual(edit_modal.capa_type,
                         "Custom Evaluated Script")  # precondition check
        edit_modal.capa_type = "Dropdown"
        library_container.save_settings()

        # Library should contain single Dropdown problem, so now there should be no errors again
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

    def test_not_enough_children_blocks(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I set Problem Type selector so "Any"
        Then I can see that "No matching content" warning is shown
        """
        expected_tpl = "The specified library is configured to fetch {count} problems, " \
                       "but there are only {actual} matching problems."

        library_container = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[1])

        # precondition check - assert block is configured fine
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser,
                                                library_container.locator)
        edit_modal.count = 50
        library_container.save_settings()

        self.assertTrue(library_container.has_validation_warning)
        self.assertIn(
            expected_tpl.format(count=50,
                                actual=len(self.library_fixture.children)),
            library_container.validation_warning_text)

    def test_settings_overrides(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And when I click the "View" link
        Then I can see a preview of the blocks drawn from the library.

        When I edit one of the blocks to change a setting such as "display_name",
        Then I can see the new setting is overriding the library version.

        When I subsequently click to refresh the content with the latest from the library,
        Then I can see that the overrided version of the setting is preserved.

        When I click to edit the block and reset the setting,
        then I can see that the setting's field defaults back to the library version.
        """
        block_wrapper_unit_page = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[0].children[0])
        container_page = block_wrapper_unit_page.go_to_container()
        library_block = self._get_library_xblock_wrapper(
            container_page.xblocks[0])

        self.assertFalse(library_block.has_validation_message)
        self.assertEqual(len(library_block.children), 3)

        block = library_block.children[0]
        self.assertIn(block.name, ("Html1", "Html2", "Html3"))
        name_default = block.name

        block.edit()
        new_display_name = "A new name for this HTML block"
        block.set_field_val("Display Name", new_display_name)
        block.save_settings()

        self.assertEqual(block.name, new_display_name)

        # Create a new block, causing a new library version:
        self.library_fixture.create_xblock(
            self.library_fixture.library_location,
            XBlockFixtureDesc("html", "Html4"))

        container_page.visit()  # Reload
        self.assertTrue(library_block.has_validation_warning)

        library_block.refresh_children()
        container_page.wait_for_page()  # Wait for the page to reload

        self.assertEqual(len(library_block.children), 4)
        self.assertEqual(block.name, new_display_name)

        # Reset:
        block.edit()
        block.reset_field_val("Display Name")
        block.save_settings()
        self.assertEqual(block.name, name_default)

    def test_cannot_manage(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And when I click the "View" link
        Then I can see a preview of the blocks drawn from the library.

        And I do not see a duplicate button
        And I do not see a delete button
        """
        block_wrapper_unit_page = self._get_library_xblock_wrapper(
            self.unit_page.xblocks[0].children[0])
        container_page = block_wrapper_unit_page.go_to_container()

        for block in container_page.xblocks:
            self.assertFalse(block.has_duplicate_button)
            self.assertFalse(block.has_delete_button)
            self.assertFalse(block.has_edit_visibility_button)
コード例 #29
0
    def setUp(self):
        """
        Initializes the components (page objects, courses, users) for this test suite
        """
        # Some parameters are provided by the parent setUp() routine, such as the following:
        # self.course_id, self.course_info, self.unique_id
        super(BaseLmsDashboardTestMultiple, self).setUp()

        # Load page objects for use by the tests
        self.dashboard_page = DashboardPage(self.browser)

        # Configure some aspects of the test course and install the settings into the course
        self.courses = {
            'A': {
                'org': 'test_org',
                'number': self.unique_id,
                'run': 'test_run_A',
                'display_name': 'Test Course A',
                'enrollment_mode': 'audit',
                'cert_name_long': 'Certificate of Audit Achievement'
            },
            'B': {
                'org': 'test_org',
                'number': self.unique_id,
                'run': 'test_run_B',
                'display_name': 'Test Course B',
                'enrollment_mode': 'verified',
                'cert_name_long': 'Certificate of Verified Achievement'
            },
            'C': {
                'org': 'test_org',
                'number': self.unique_id,
                'run': 'test_run_C',
                'display_name': 'Test Course C',
                'enrollment_mode': 'credit',
                'cert_name_long': 'Certificate of Credit Achievement'
            }
        }

        self.username = "******".format(uuid=self.unique_id[0:6])
        self.email = "{user}@example.com".format(user=self.username)

        self.course_keys = {}
        self.course_fixtures = {}

        for key, value in self.courses.iteritems():
            course_key = generate_course_key(
                value['org'],
                value['number'],
                value['run'],
            )

            course_fixture = CourseFixture(
                value['org'],
                value['number'],
                value['run'],
                value['display_name'],
            )

            course_fixture.add_advanced_settings({
                u"social_sharing_url": {
                    u"value": "http://custom/course/url"
                },
                u"cert_name_long": {
                    u"value": value['cert_name_long']
                }
            })

            course_fixture.install()

            self.course_keys[key] = course_key
            self.course_fixtures[key] = course_fixture

            # Create the test user, register them for the course, and authenticate
            AutoAuthPage(self.browser,
                         username=self.username,
                         email=self.email,
                         course_id=course_key,
                         enrollment_mode=value['enrollment_mode']).visit()

        # Navigate the authenticated, enrolled user to the dashboard page and get testing!
        self.dashboard_page.visit()
コード例 #30
0
    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)
コード例 #31
0
class SignUpAndSignInTest(UniqueCourseTest):
    """
    Test studio sign-up and sign-in
    """
    def setUp(self):  # pylint: disable=arguments-differ
        super(SignUpAndSignInTest, self).setUp()
        self.sign_up_page = SignupPage(self.browser)
        self.login_page = LoginPage(self.browser)

        self.course_outline_page = CourseOutlinePage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])
        self.course_outline_sign_in_redirect_page = CourseOutlineSignInRedirectPage(
            self.browser, self.course_info['org'], self.course_info['number'],
            self.course_info['run'])

        self.course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name'],
        )
        self.user = None

    def install_course_fixture(self):
        """
        Install a course fixture
        """
        self.course_fixture.install()
        self.user = self.course_fixture.user

    def test_sign_up_from_home(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        And I press the Create My Account button on the registration form
        Then I should see an email verification prompt
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        unique_number = uuid.uuid4().hex[:4]
        registration_dic = {
            '#email': '{}[email protected]'.format(unique_number),
            '#name': '{}-name'.format(unique_number),
            '#username': '******'.format(unique_number),
            '#password': '******'.format(unique_number),
        }
        # Register the user.
        self.sign_up_page.sign_up_user(registration_dic)
        home = HomePage(self.browser)
        home.wait_for_page()

    def test_login_with_valid_redirect(self):
        """
        Scenario: Login with a valid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/course/slashes:MITx+999+Robot_Super_Course"
        And I should see that the path is "/signin?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
        When I fill in and submit the signin form
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        # Get the url, browser should land here after sign in.
        course_url = self.course_outline_sign_in_redirect_page.url
        self.course_outline_sign_in_redirect_page.visit()
        # Login
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, course_url)

    def test_login_with_invalid_redirect(self):
        """
        Scenario: Login with an invalid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/signin?next=http://www.google.com/"
        When I fill in and submit the signin form
        Then I should see that the path is "/home/"
        """
        self.install_course_fixture()
        # Visit course
        self.course_outline_sign_in_redirect_page.visit()
        # Change redirect url
        self.browser.get(
            self.browser.current_url.split('=')[0] + '=http://www.google.com')
        # Login
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'], self.user['password'])
        home = HomePage(self.browser)
        home.wait_for_page()
        self.assertEqual(self.browser.current_url, home.url)

    def test_login_with_mistyped_credentials(self):
        """
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the Studio homepage
        When I click the link with the text "Sign In"
        Then I should see that the path is "/signin"
        And I should not see a login error message
        And I fill in and submit the signin form incorrectly
        Then I should see a login error message
        And I edit the password field
        Then I should not see a login error message
        And I submit the signin form
        And I wait for "2" seconds
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        self.course_outline_sign_in_redirect_page.visit()
        # Verify login_error is not present
        self.course_outline_sign_in_redirect_page.wait_for_element_absence(
            '#login_error', 'Login error not be present')
        # Login with wrong credentials
        self.course_outline_sign_in_redirect_page.login(self.user['email'],
                                                        'wrong_password',
                                                        expect_success=False)
        # Verify that login error is shown
        self.course_outline_sign_in_redirect_page.wait_for_element_visibility(
            '#login_error', 'Login error is visible')
        # Change the password
        self.course_outline_sign_in_redirect_page.fill_field(
            'input#password', 'changed_password')
        # Login error should not be visible
        self.course_outline_sign_in_redirect_page.wait_for_element_invisibility(
            '#login_error', 'Login error is not visible')
        # Login with correct credentials
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url,
                         self.course_outline_page.url)
コード例 #32
0
    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)
コード例 #33
0
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()
コード例 #34
0
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()
コード例 #35
0
class LibraryContentTestBase(UniqueCourseTest):
    """ Base class for library content block tests """
    USERNAME = "******"
    EMAIL = "*****@*****.**"

    STAFF_USERNAME = "******"
    STAFF_EMAIL = "*****@*****.**"
    shard = 10

    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,
            u'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': six.text_type(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()
        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()
コード例 #36
0
class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest, TestWithSearchIndexMixin):
    """
    Test Library Content block in LMS
    """
    def setUp(self):
        """
        Install library with some content and a course using fixtures
        """
        self._create_search_index()
        super(StudioLibraryContainerTest, self).setUp()
        # Also create a course:
        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)
        self.course_fixture.install()
        self.outline = CourseOutlinePage(
            self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
        )

        self.outline.visit()
        subsection = self.outline.section(SECTION_NAME).subsection(SUBSECTION_NAME)
        self.unit_page = subsection.expand_subsection().unit(UNIT_NAME).go_to()

    def tearDown(self):
        """ Tear down method: remove search index backing file """
        self._cleanup_index_file()
        super(StudioLibraryContainerTest, self).tearDown()

    def populate_library_fixture(self, library_fixture):
        """
        Populate the children of the test course fixture.
        """
        library_fixture.add_children(
            XBlockFixtureDesc("html", "Html1"),
            XBlockFixtureDesc("html", "Html2"),
            XBlockFixtureDesc("html", "Html3"),
        )

    def populate_course_fixture(self, course_fixture):
        """ Install a course with sections/problems, tabs, updates, and handouts """
        library_content_metadata = {
            'source_library_id': unicode(self.library_key),
            'mode': 'random',
            'max_count': 1,
        }

        course_fixture.add_children(
            XBlockFixtureDesc('chapter', SECTION_NAME).add_children(
                XBlockFixtureDesc('sequential', SUBSECTION_NAME).add_children(
                    XBlockFixtureDesc('vertical', UNIT_NAME).add_children(
                        XBlockFixtureDesc('library_content', "Library Content", metadata=library_content_metadata)
                    )
                )
            )
        )

    def _get_library_xblock_wrapper(self, xblock):
        """
        Wraps xblock into :class:`...pages.studio.library.StudioLibraryContainerXBlockWrapper`
        """
        return StudioLibraryContainerXBlockWrapper.from_xblock_wrapper(xblock)

    @ddt.data(1, 2, 3)
    def test_can_edit_metadata(self, max_count):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I edit library content metadata and save it
        Then I can ensure that data is persisted
        """
        library_name = self.library_info['display_name']
        library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])
        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        edit_modal.library_name = library_name
        edit_modal.count = max_count

        library_container.save_settings()  # saving settings

        # open edit window again to verify changes are persistent
        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        self.assertEqual(edit_modal.library_name, library_name)
        self.assertEqual(edit_modal.count, max_count)

    def test_no_library_shows_library_not_configured(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I edit to select "No Library"
        Then I can see that library content block is misconfigured
        """
        expected_text = 'A library has not yet been selected.'
        expected_action = 'Select a Library'
        library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])

        # precondition check - the library block should be configured before we remove the library setting
        self.assertFalse(library_container.has_validation_not_configured_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        edit_modal.library_name = "No Library Selected"
        library_container.save_settings()

        self.assertTrue(library_container.has_validation_not_configured_warning)
        self.assertIn(expected_text, library_container.validation_not_configured_warning_text)
        self.assertIn(expected_action, library_container.validation_not_configured_warning_text)

    def test_out_of_date_message(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        Then I update the library being used
        Then I refresh the page
        Then I can see that library content block needs to be updated
        When I click on the update link
        Then I can see that the content no longer needs to be updated
        """
        # Formerly flaky: see TE-745
        expected_text = "This component is out of date. The library has new content."
        library_block = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])

        self.assertFalse(library_block.has_validation_warning)
        # Removed this assert until a summary message is added back to the author view (SOL-192)
        #self.assertIn("3 matching components", library_block.author_content)

        self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc("html", "Html4"))

        self.unit_page.visit()  # Reload the page

        self.assertTrue(library_block.has_validation_warning)
        self.assertIn(expected_text, library_block.validation_warning_text)

        library_block.refresh_children()

        self.unit_page.wait_for_page()  # Wait for the page to reload
        library_block = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])

        self.assertFalse(library_block.has_validation_message)
        # Removed this assert until a summary message is added back to the author view (SOL-192)
        #self.assertIn("4 matching components", library_block.author_content)

    def test_no_content_message(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I set Problem Type selector so that no libraries have matching content
        Then I can see that "No matching content" warning is shown
        When I set Problem Type selector so that there is matching content
        Then I can see that warning messages are not shown
        """
        # Add a single "Dropdown" type problem to the library (which otherwise has only HTML blocks):
        self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc(
            "problem", "Dropdown",
            data=textwrap.dedent("""
                <problem>
                    <p>Dropdown</p>
                    <optionresponse><optioninput label="Dropdown" options="('1', '2')" correct="'2'"></optioninput></optionresponse>
                </problem>
                """)
        ))

        expected_text = 'There are no matching problem types in the specified libraries. Select another problem type'

        library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])

        # precondition check - assert library has children matching filter criteria
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        self.assertEqual(edit_modal.capa_type, "Any Type")  # precondition check
        edit_modal.capa_type = "Custom Evaluated Script"

        library_container.save_settings()

        self.assertTrue(library_container.has_validation_warning)
        self.assertIn(expected_text, library_container.validation_warning_text)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        self.assertEqual(edit_modal.capa_type, "Custom Evaluated Script")  # precondition check
        edit_modal.capa_type = "Dropdown"
        library_container.save_settings()

        # Library should contain single Dropdown problem, so now there should be no errors again
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

    def test_not_enough_children_blocks(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And I set Problem Type selector so "Any"
        Then I can see that "No matching content" warning is shown
        """
        expected_tpl = "The specified library is configured to fetch {count} problems, " \
                       "but there are only {actual} matching problems."

        library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1])

        # precondition check - assert block is configured fine
        self.assertFalse(library_container.has_validation_error)
        self.assertFalse(library_container.has_validation_warning)

        library_container.edit()
        edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator)
        edit_modal.count = 50
        library_container.save_settings()

        self.assertTrue(library_container.has_validation_warning)
        self.assertIn(
            expected_tpl.format(count=50, actual=len(self.library_fixture.children)),
            library_container.validation_warning_text
        )

    def test_settings_overrides(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And when I click the "View" link
        Then I can see a preview of the blocks drawn from the library.

        When I edit one of the blocks to change a setting such as "display_name",
        Then I can see the new setting is overriding the library version.

        When I subsequently click to refresh the content with the latest from the library,
        Then I can see that the overrided version of the setting is preserved.

        When I click to edit the block and reset the setting,
        then I can see that the setting's field defaults back to the library version.
        """
        block_wrapper_unit_page = self._get_library_xblock_wrapper(self.unit_page.xblocks[0].children[0])
        container_page = block_wrapper_unit_page.go_to_container()
        library_block = self._get_library_xblock_wrapper(container_page.xblocks[0])

        self.assertFalse(library_block.has_validation_message)
        self.assertEqual(len(library_block.children), 3)

        block = library_block.children[0]
        self.assertIn(block.name, ("Html1", "Html2", "Html3"))
        name_default = block.name

        block.edit()
        new_display_name = "A new name for this HTML block"
        block.set_field_val("Display Name", new_display_name)
        block.save_settings()

        self.assertEqual(block.name, new_display_name)

        # Create a new block, causing a new library version:
        self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc("html", "Html4"))

        container_page.visit()  # Reload
        self.assertTrue(library_block.has_validation_warning)

        library_block.refresh_children()
        container_page.wait_for_page()  # Wait for the page to reload

        self.assertEqual(len(library_block.children), 4)
        self.assertEqual(block.name, new_display_name)

        # Reset:
        block.edit()
        block.reset_field_val("Display Name")
        block.save_settings()
        self.assertEqual(block.name, name_default)

    def test_cannot_manage(self):
        """
        Scenario: Given I have a library, a course and library content xblock in a course
        When I go to studio unit page for library content block
        And when I click the "View" link
        Then I can see a preview of the blocks drawn from the library.

        And I do not see a duplicate button
        And I do not see a delete button
        """
        block_wrapper_unit_page = self._get_library_xblock_wrapper(self.unit_page.xblocks[0].children[0])
        container_page = block_wrapper_unit_page.go_to_container()

        for block in container_page.xblocks:
            self.assertFalse(block.has_duplicate_button)
            self.assertFalse(block.has_delete_button)
            self.assertFalse(block.has_edit_visibility_button)