TNL-329 Client-side work for displaying cohort description.
This commit is contained in:
committed by
cahrens
parent
f72974d4df
commit
b4c826e747
82
common/test/acceptance/pages/lms/instructor_dashboard.py
Normal file
82
common/test/acceptance/pages/lms/instructor_dashboard.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Instructor (2) dashboard page.
|
||||
"""
|
||||
|
||||
from bok_choy.page_object import PageObject
|
||||
from .course_page import CoursePage
|
||||
|
||||
|
||||
class InstructorDashboardPage(CoursePage):
|
||||
"""
|
||||
Instructor dashboard, where course staff can manage a course.
|
||||
"""
|
||||
url_path = "instructor"
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='div.instructor-dashboard-wrapper-2').present
|
||||
|
||||
def select_membership(self):
|
||||
"""
|
||||
Selects the membership tab and returns the MembershipSection
|
||||
"""
|
||||
self.q(css='a[data-section=membership]').first.click()
|
||||
membership_section = MembershipPage(self.browser)
|
||||
membership_section.wait_for_page()
|
||||
return membership_section
|
||||
|
||||
|
||||
class MembershipPage(PageObject):
|
||||
"""
|
||||
Membership section of the Instructor dashboard.
|
||||
"""
|
||||
url = None
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='a[data-section=membership].active-section').present
|
||||
|
||||
def _get_cohort_options(self):
|
||||
"""
|
||||
Returns the available options in the cohort dropdown, including the initial "Select a cohort".
|
||||
"""
|
||||
return self.q(css=".cohort-management #cohort-select option")
|
||||
|
||||
def _name_without_count(self, name_with_count):
|
||||
"""
|
||||
Returns the name of the cohort with the count information excluded.
|
||||
"""
|
||||
return name_with_count.split(' (')[0]
|
||||
|
||||
def get_cohorts(self):
|
||||
"""
|
||||
Returns, as a list, the names of the available cohorts in the drop-down, filtering out "Select a cohort".
|
||||
"""
|
||||
return [
|
||||
self._name_without_count(opt.text)
|
||||
for opt in self._get_cohort_options().filter(lambda el: el.get_attribute('value') != "")
|
||||
]
|
||||
|
||||
def get_selected_cohort(self):
|
||||
"""
|
||||
Returns the name of the selected cohort.
|
||||
"""
|
||||
return self._name_without_count(
|
||||
self._get_cohort_options().filter(lambda el: el.is_selected()).first.text[0]
|
||||
)
|
||||
|
||||
def select_cohort(self, cohort_name):
|
||||
"""
|
||||
Selects the given cohort in the drop-down.
|
||||
"""
|
||||
self.q(css=".cohort-management #cohort-select option").filter(
|
||||
lambda el: self._name_without_count(el.text) == cohort_name
|
||||
).first.click()
|
||||
|
||||
def get_cohort_group_setup(self):
|
||||
"""
|
||||
Returns the description of the current cohort
|
||||
"""
|
||||
return self.q(css='.cohort-management-group-setup .setup-value').first.text[0]
|
||||
|
||||
def select_edit_settings(self):
|
||||
self.q(css=".action-edit").first.click()
|
||||
@@ -3,11 +3,11 @@ Tests related to the cohorting feature.
|
||||
"""
|
||||
from uuid import uuid4
|
||||
|
||||
from helpers import BaseDiscussionMixin
|
||||
from ...pages.lms.auto_auth import AutoAuthPage
|
||||
from .helpers import BaseDiscussionMixin
|
||||
from ..lms.helpers import CohortTestMixin
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...pages.lms.auto_auth import AutoAuthPage
|
||||
from ...fixtures.course import (CourseFixture, XBlockFixtureDesc)
|
||||
from ...fixtures import LMS_BASE_URL
|
||||
|
||||
from ...pages.lms.discussion import (DiscussionTabSingleThreadPage, InlineDiscussionThreadPage, InlineDiscussionPage)
|
||||
from ...pages.lms.courseware import CoursewarePage
|
||||
@@ -17,7 +17,7 @@ from nose.plugins.attrib import attr
|
||||
|
||||
class NonCohortedDiscussionTestMixin(BaseDiscussionMixin):
|
||||
"""
|
||||
Mixin for tests of non-cohorted courses.
|
||||
Mixin for tests of discussion in non-cohorted courses.
|
||||
"""
|
||||
def setup_cohorts(self):
|
||||
"""
|
||||
@@ -30,36 +30,17 @@ class NonCohortedDiscussionTestMixin(BaseDiscussionMixin):
|
||||
self.assertEquals(self.thread_page.get_group_visibility_label(), "This post is visible to everyone.")
|
||||
|
||||
|
||||
class CohortedDiscussionTestMixin(BaseDiscussionMixin):
|
||||
class CohortedDiscussionTestMixin(BaseDiscussionMixin, CohortTestMixin):
|
||||
"""
|
||||
Mixin for tests of cohorted courses.
|
||||
Mixin for tests of discussion in cohorted courses.
|
||||
"""
|
||||
def add_cohort(self, name):
|
||||
"""
|
||||
Adds a cohort group by name, returning the ID for the group.
|
||||
"""
|
||||
url = LMS_BASE_URL + "/courses/" + self.course_fixture._course_key + '/cohorts/add'
|
||||
data = {"name": name}
|
||||
response = self.course_fixture.session.post(url, data=data, headers=self.course_fixture.headers)
|
||||
self.assertTrue(response.ok, "Failed to create cohort")
|
||||
return response.json()['cohort']['id']
|
||||
|
||||
def setup_cohorts(self):
|
||||
"""
|
||||
Sets up the course to use cohorting with a single defined cohort group.
|
||||
"""
|
||||
self.course_fixture._update_xblock(self.course_fixture._course_location, {
|
||||
"metadata": {
|
||||
u"cohort_config": {
|
||||
"auto_cohort_groups": [],
|
||||
"auto_cohort": False,
|
||||
"cohorted_discussions": [],
|
||||
"cohorted": True
|
||||
},
|
||||
},
|
||||
})
|
||||
self.setup_cohort_config(self.course_fixture)
|
||||
self.cohort_1_name = "Cohort Group 1"
|
||||
self.cohort_1_id = self.add_cohort(self.cohort_1_name)
|
||||
self.cohort_1_id = self.add_manual_cohort(self.course_fixture, self.cohort_1_name)
|
||||
|
||||
def test_cohort_visibility_label(self):
|
||||
# Must be moderator to view content in a cohort other than your own
|
||||
|
||||
@@ -29,7 +29,7 @@ from ...fixtures.discussion import (
|
||||
SearchResult,
|
||||
)
|
||||
|
||||
from helpers import BaseDiscussionMixin
|
||||
from .helpers import BaseDiscussionMixin
|
||||
|
||||
|
||||
class DiscussionResponsePaginationTestMixin(BaseDiscussionMixin):
|
||||
|
||||
0
common/test/acceptance/tests/lms/__init__.py
Normal file
0
common/test/acceptance/tests/lms/__init__.py
Normal file
35
common/test/acceptance/tests/lms/helpers.py
Normal file
35
common/test/acceptance/tests/lms/helpers.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
Helper functions and classes for LMS tests.
|
||||
"""
|
||||
|
||||
from ...fixtures import LMS_BASE_URL
|
||||
|
||||
|
||||
class CohortTestMixin(object):
|
||||
"""
|
||||
Mixin for tests of cohorted courses
|
||||
"""
|
||||
def setup_cohort_config(self, course_fixture, auto_cohort_groups=None):
|
||||
"""
|
||||
Sets up the course to use cohorting with the given list of auto_cohort_groups.
|
||||
If auto_cohort_groups is None, no auto cohort groups are set.
|
||||
"""
|
||||
course_fixture._update_xblock(course_fixture._course_location, {
|
||||
"metadata": {
|
||||
u"cohort_config": {
|
||||
"auto_cohort_groups": auto_cohort_groups or [],
|
||||
"cohorted_discussions": [],
|
||||
"cohorted": True
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
def add_manual_cohort(self, course_fixture, name):
|
||||
"""
|
||||
Adds a cohort group by name, returning the ID for the group.
|
||||
"""
|
||||
url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/add'
|
||||
data = {"name": name}
|
||||
response = course_fixture.session.post(url, data=data, headers=course_fixture.headers)
|
||||
self.assertTrue(response.ok, "Failed to create cohort")
|
||||
return response.json()['cohort']['id']
|
||||
@@ -1,26 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E2E tests for the LMS.
|
||||
End-to-end tests for the LMS.
|
||||
"""
|
||||
|
||||
from textwrap import dedent
|
||||
from unittest import skip
|
||||
|
||||
from bok_choy.web_app_test import WebAppTest
|
||||
from .helpers import UniqueCourseTest, load_data_str
|
||||
from ..pages.lms.auto_auth import AutoAuthPage
|
||||
from ..pages.lms.find_courses import FindCoursesPage
|
||||
from ..pages.lms.course_about import CourseAboutPage
|
||||
from ..pages.lms.course_info import CourseInfoPage
|
||||
from ..pages.lms.tab_nav import TabNavPage
|
||||
from ..pages.lms.course_nav import CourseNavPage
|
||||
from ..pages.lms.progress import ProgressPage
|
||||
from ..pages.lms.dashboard import DashboardPage
|
||||
from ..pages.lms.problem import ProblemPage
|
||||
from ..pages.lms.video.video import VideoPage
|
||||
from ..pages.xblock.acid import AcidView
|
||||
from ..pages.lms.courseware import CoursewarePage
|
||||
from ..fixtures.course import CourseFixture, XBlockFixtureDesc, CourseUpdateDesc
|
||||
from ..helpers import UniqueCourseTest, load_data_str
|
||||
from ...pages.lms.auto_auth import AutoAuthPage
|
||||
from ...pages.lms.find_courses import FindCoursesPage
|
||||
from ...pages.lms.course_about import CourseAboutPage
|
||||
from ...pages.lms.course_info import CourseInfoPage
|
||||
from ...pages.lms.tab_nav import TabNavPage
|
||||
from ...pages.lms.course_nav import CourseNavPage
|
||||
from ...pages.lms.progress import ProgressPage
|
||||
from ...pages.lms.dashboard import DashboardPage
|
||||
from ...pages.lms.problem import ProblemPage
|
||||
from ...pages.lms.video.video import VideoPage
|
||||
from ...pages.lms.courseware import CoursewarePage
|
||||
from ...fixtures.course import CourseFixture, XBlockFixtureDesc, CourseUpdateDesc
|
||||
|
||||
|
||||
class RegistrationTest(UniqueCourseTest):
|
||||
@@ -267,7 +266,7 @@ class VideoTest(UniqueCourseTest):
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('video', 'Video')
|
||||
)))).install()
|
||||
)))).install()
|
||||
|
||||
# Auto-auth register for the course
|
||||
AutoAuthPage(self.browser, course_id=self.course_id).visit()
|
||||
@@ -311,115 +310,6 @@ class VideoTest(UniqueCourseTest):
|
||||
self.assertGreaterEqual(self.video.duration, self.video.elapsed_time)
|
||||
|
||||
|
||||
class XBlockAcidBase(UniqueCourseTest):
|
||||
"""
|
||||
Base class for tests that verify that XBlock integration is working correctly
|
||||
"""
|
||||
__test__ = False
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create a unique identifier for the course used in this test.
|
||||
"""
|
||||
# Ensure that the superclass sets up
|
||||
super(XBlockAcidBase, self).setUp()
|
||||
|
||||
self.setup_fixtures()
|
||||
|
||||
AutoAuthPage(self.browser, course_id=self.course_id).visit()
|
||||
|
||||
self.course_info_page = CourseInfoPage(self.browser, self.course_id)
|
||||
self.tab_nav = TabNavPage(self.browser)
|
||||
|
||||
def validate_acid_block_view(self, acid_block):
|
||||
"""
|
||||
Verify that the LMS view for the Acid Block is correct
|
||||
"""
|
||||
self.assertTrue(acid_block.init_fn_passed)
|
||||
self.assertTrue(acid_block.resource_url_passed)
|
||||
self.assertTrue(acid_block.scope_passed('user_state'))
|
||||
self.assertTrue(acid_block.scope_passed('user_state_summary'))
|
||||
self.assertTrue(acid_block.scope_passed('preferences'))
|
||||
self.assertTrue(acid_block.scope_passed('user_info'))
|
||||
|
||||
def test_acid_block(self):
|
||||
"""
|
||||
Verify that all expected acid block tests pass in the lms.
|
||||
"""
|
||||
|
||||
self.course_info_page.visit()
|
||||
self.tab_nav.go_to_tab('Courseware')
|
||||
|
||||
acid_block = AcidView(self.browser, '.xblock-student_view[data-block-type=acid]')
|
||||
self.validate_acid_block_view(acid_block)
|
||||
|
||||
|
||||
class XBlockAcidNoChildTest(XBlockAcidBase):
|
||||
"""
|
||||
Tests of an AcidBlock with no children
|
||||
"""
|
||||
__test__ = True
|
||||
|
||||
def setup_fixtures(self):
|
||||
course_fix = CourseFixture(
|
||||
self.course_info['org'],
|
||||
self.course_info['number'],
|
||||
self.course_info['run'],
|
||||
self.course_info['display_name']
|
||||
)
|
||||
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('acid', 'Acid Block')
|
||||
)
|
||||
)
|
||||
)
|
||||
).install()
|
||||
|
||||
@skip('Flakey test, TE-401')
|
||||
def test_acid_block(self):
|
||||
super(XBlockAcidNoChildTest, self).test_acid_block()
|
||||
|
||||
|
||||
class XBlockAcidChildTest(XBlockAcidBase):
|
||||
"""
|
||||
Tests of an AcidBlock with children
|
||||
"""
|
||||
__test__ = True
|
||||
|
||||
def setup_fixtures(self):
|
||||
course_fix = CourseFixture(
|
||||
self.course_info['org'],
|
||||
self.course_info['number'],
|
||||
self.course_info['run'],
|
||||
self.course_info['display_name']
|
||||
)
|
||||
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('acid_parent', 'Acid Parent Block').add_children(
|
||||
XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}),
|
||||
XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}),
|
||||
XBlockFixtureDesc('html', 'Html Child', data="<html>Contents</html>"),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
).install()
|
||||
|
||||
def validate_acid_block_view(self, acid_block):
|
||||
super(XBlockAcidChildTest, self).validate_acid_block_view()
|
||||
self.assertTrue(acid_block.child_tests_passed)
|
||||
|
||||
@skip('This will fail until we fix support of children in pure XBlocks')
|
||||
def test_acid_block(self):
|
||||
super(XBlockAcidChildTest, self).test_acid_block()
|
||||
|
||||
|
||||
class VisibleToStaffOnlyTest(UniqueCourseTest):
|
||||
"""
|
||||
Tests that content with visible_to_staff_only set to True cannot be viewed by students.
|
||||
@@ -574,7 +464,8 @@ class ProblemExecutionTest(UniqueCourseTest):
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('problem', 'Python Problem', data=dedent("""\
|
||||
XBlockFixtureDesc('problem', 'Python Problem', data=dedent(
|
||||
"""\
|
||||
<problem>
|
||||
<script type="loncapa/python">
|
||||
from number_helpers import seventeen, fortytwo
|
||||
@@ -594,7 +485,7 @@ class ProblemExecutionTest(UniqueCourseTest):
|
||||
</customresponse>
|
||||
</problem>
|
||||
"""
|
||||
)),
|
||||
))
|
||||
)
|
||||
)
|
||||
).install()
|
||||
122
common/test/acceptance/tests/lms/test_lms_acid_xblock.py
Normal file
122
common/test/acceptance/tests/lms/test_lms_acid_xblock.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
End-to-end tests for the LMS.
|
||||
"""
|
||||
|
||||
from unittest import skip
|
||||
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...pages.lms.auto_auth import AutoAuthPage
|
||||
from ...pages.lms.course_info import CourseInfoPage
|
||||
from ...pages.lms.tab_nav import TabNavPage
|
||||
from ...pages.xblock.acid import AcidView
|
||||
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
|
||||
|
||||
class XBlockAcidBase(UniqueCourseTest):
|
||||
"""
|
||||
Base class for tests that verify that XBlock integration is working correctly
|
||||
"""
|
||||
__test__ = False
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create a unique identifier for the course used in this test.
|
||||
"""
|
||||
# Ensure that the superclass sets up
|
||||
super(XBlockAcidBase, self).setUp()
|
||||
|
||||
self.setup_fixtures()
|
||||
|
||||
AutoAuthPage(self.browser, course_id=self.course_id).visit()
|
||||
|
||||
self.course_info_page = CourseInfoPage(self.browser, self.course_id)
|
||||
self.tab_nav = TabNavPage(self.browser)
|
||||
|
||||
def validate_acid_block_view(self, acid_block):
|
||||
"""
|
||||
Verify that the LMS view for the Acid Block is correct
|
||||
"""
|
||||
self.assertTrue(acid_block.init_fn_passed)
|
||||
self.assertTrue(acid_block.resource_url_passed)
|
||||
self.assertTrue(acid_block.scope_passed('user_state'))
|
||||
self.assertTrue(acid_block.scope_passed('user_state_summary'))
|
||||
self.assertTrue(acid_block.scope_passed('preferences'))
|
||||
self.assertTrue(acid_block.scope_passed('user_info'))
|
||||
|
||||
def test_acid_block(self):
|
||||
"""
|
||||
Verify that all expected acid block tests pass in the lms.
|
||||
"""
|
||||
|
||||
self.course_info_page.visit()
|
||||
self.tab_nav.go_to_tab('Courseware')
|
||||
|
||||
acid_block = AcidView(self.browser, '.xblock-student_view[data-block-type=acid]')
|
||||
self.validate_acid_block_view(acid_block)
|
||||
|
||||
|
||||
class XBlockAcidNoChildTest(XBlockAcidBase):
|
||||
"""
|
||||
Tests of an AcidBlock with no children
|
||||
"""
|
||||
__test__ = True
|
||||
|
||||
def setup_fixtures(self):
|
||||
course_fix = CourseFixture(
|
||||
self.course_info['org'],
|
||||
self.course_info['number'],
|
||||
self.course_info['run'],
|
||||
self.course_info['display_name']
|
||||
)
|
||||
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('acid', 'Acid Block')
|
||||
)
|
||||
)
|
||||
)
|
||||
).install()
|
||||
|
||||
@skip('Flakey test, TE-401')
|
||||
def test_acid_block(self):
|
||||
super(XBlockAcidNoChildTest, self).test_acid_block()
|
||||
|
||||
|
||||
class XBlockAcidChildTest(XBlockAcidBase):
|
||||
"""
|
||||
Tests of an AcidBlock with children
|
||||
"""
|
||||
__test__ = True
|
||||
|
||||
def setup_fixtures(self):
|
||||
course_fix = CourseFixture(
|
||||
self.course_info['org'],
|
||||
self.course_info['number'],
|
||||
self.course_info['run'],
|
||||
self.course_info['display_name']
|
||||
)
|
||||
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection').add_children(
|
||||
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
|
||||
XBlockFixtureDesc('acid_parent', 'Acid Parent Block').add_children(
|
||||
XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}),
|
||||
XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}),
|
||||
XBlockFixtureDesc('html', 'Html Child', data="<html>Contents</html>"),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
).install()
|
||||
|
||||
def validate_acid_block_view(self, acid_block):
|
||||
super(XBlockAcidChildTest, self).validate_acid_block_view()
|
||||
self.assertTrue(acid_block.child_tests_passed)
|
||||
|
||||
@skip('This will fail until we fix support of children in pure XBlocks')
|
||||
def test_acid_block(self):
|
||||
super(XBlockAcidChildTest, self).test_acid_block()
|
||||
70
common/test/acceptance/tests/lms/test_lms_cohorts.py
Normal file
70
common/test/acceptance/tests/lms/test_lms_cohorts.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
End-to-end tests related to the cohort management on the LMS Instructor Dashboard
|
||||
"""
|
||||
|
||||
from .helpers import CohortTestMixin
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...fixtures.course import CourseFixture
|
||||
from ...pages.lms.auto_auth import AutoAuthPage
|
||||
from ...pages.lms.instructor_dashboard import InstructorDashboardPage
|
||||
from ...pages.studio.settings_advanced import AdvancedSettingsPage
|
||||
|
||||
|
||||
class CohortTest(UniqueCourseTest, CohortTestMixin):
|
||||
"""
|
||||
Tests for cohort management on the LMS Instructor Dashboard
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up a cohorted course
|
||||
"""
|
||||
super(CohortTest, self).setUp()
|
||||
|
||||
# create course with cohorts
|
||||
self.manual_cohort_name = "ManualCohort1"
|
||||
self.auto_cohort_name = "AutoCohort1"
|
||||
self.course_fixture = CourseFixture(**self.course_info).install()
|
||||
self.setup_cohort_config(self.course_fixture, auto_cohort_groups=[self.auto_cohort_name])
|
||||
self.add_manual_cohort(self.course_fixture, self.manual_cohort_name)
|
||||
|
||||
# login as an instructor
|
||||
self.user_id = AutoAuthPage(self.browser, course_id=self.course_id, staff=True).visit().get_user_id()
|
||||
|
||||
# go to the membership page on the instructor dashboard
|
||||
instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
|
||||
instructor_dashboard_page.visit()
|
||||
self.membership_page = instructor_dashboard_page.select_membership()
|
||||
|
||||
def verify_cohort_description(self, cohort_name, expected_description):
|
||||
"""
|
||||
Selects the cohort with the given name and verifies the expected description is presented.
|
||||
"""
|
||||
self.membership_page.select_cohort(cohort_name)
|
||||
self.assertEquals(self.membership_page.get_selected_cohort(), cohort_name)
|
||||
self.assertIn(expected_description, self.membership_page.get_cohort_group_setup())
|
||||
|
||||
def test_cohort_description(self):
|
||||
"""
|
||||
Tests the description presented for manual and auto cohort types.
|
||||
"""
|
||||
self.verify_cohort_description(
|
||||
self.manual_cohort_name,
|
||||
'Students are added to this group only when you provide their email addresses or usernames on this page',
|
||||
)
|
||||
self.verify_cohort_description(
|
||||
self.auto_cohort_name,
|
||||
'Students are added to this group automatically',
|
||||
)
|
||||
|
||||
def test_link_to_studio(self):
|
||||
"""
|
||||
Tests the link to the Advanced Settings page in Studio.
|
||||
"""
|
||||
self.membership_page.select_cohort(self.manual_cohort_name)
|
||||
self.membership_page.select_edit_settings()
|
||||
advanced_settings_page = AdvancedSettingsPage(
|
||||
self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
|
||||
)
|
||||
advanced_settings_page.wait_for_page()
|
||||
@@ -1,16 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E2E tests for the LMS.
|
||||
End-to-end tests for the LMS.
|
||||
"""
|
||||
import time
|
||||
|
||||
from .helpers import UniqueCourseTest
|
||||
from ..pages.studio.auto_auth import AutoAuthPage
|
||||
from ..pages.studio.overview import CourseOutlinePage
|
||||
from ..pages.lms.courseware import CoursewarePage
|
||||
from ..pages.lms.problem import ProblemPage
|
||||
from ..pages.common.logout import LogoutPage
|
||||
from ..fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...pages.studio.auto_auth import AutoAuthPage
|
||||
from ...pages.studio.overview import CourseOutlinePage
|
||||
from ...pages.lms.courseware import CoursewarePage
|
||||
from ...pages.lms.problem import ProblemPage
|
||||
from ...pages.common.logout import LogoutPage
|
||||
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
|
||||
|
||||
class CoursewareTest(UniqueCourseTest):
|
||||
@@ -77,7 +77,6 @@ class CoursewareTest(UniqueCourseTest):
|
||||
AutoAuthPage(self.browser, username=username, email=email,
|
||||
course_id=self.course_id, staff=staff).visit()
|
||||
|
||||
|
||||
def test_courseware(self):
|
||||
"""
|
||||
Test courseware if recent visited subsection become unpublished.
|
||||
@@ -1,15 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E2E tests for the LMS.
|
||||
End-to-end tests for the LMS.
|
||||
"""
|
||||
import time
|
||||
|
||||
from .helpers import UniqueCourseTest
|
||||
from ..pages.studio.auto_auth import AutoAuthPage
|
||||
from ..pages.lms.courseware import CoursewarePage
|
||||
from ..pages.lms.matlab_problem import MatlabProblemPage
|
||||
from ..fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
from ..fixtures.xqueue import XQueueResponseFixture
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...pages.studio.auto_auth import AutoAuthPage
|
||||
from ...pages.lms.courseware import CoursewarePage
|
||||
from ...pages.lms.matlab_problem import MatlabProblemPage
|
||||
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
from ...fixtures.xqueue import XQueueResponseFixture
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E2E tests for the LMS.
|
||||
End-to-end tests for the LMS.
|
||||
"""
|
||||
|
||||
from .helpers import UniqueCourseTest
|
||||
from ..pages.studio.auto_auth import AutoAuthPage
|
||||
from ..pages.lms.courseware import CoursewarePage
|
||||
from ..pages.lms.staff_view import StaffPage
|
||||
from ..fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ...pages.studio.auto_auth import AutoAuthPage
|
||||
from ...pages.lms.courseware import CoursewarePage
|
||||
from ...pages.lms.staff_view import StaffPage
|
||||
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
@@ -21,12 +21,11 @@ from django.conf import settings
|
||||
from lms.lib.xblock.runtime import quote_slashes
|
||||
from xmodule_modifiers import wrap_xblock
|
||||
from xmodule.html_module import HtmlDescriptor
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xblock.field_data import DictFieldData
|
||||
from xblock.fields import ScopeIds
|
||||
from courseware.access import has_access
|
||||
from courseware.courses import get_course_by_id, get_cms_course_link
|
||||
from courseware.courses import get_course_by_id, get_studio_url
|
||||
from django_comment_client.utils import has_forum_access
|
||||
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
|
||||
from student.models import CourseEnrollment
|
||||
@@ -51,7 +50,6 @@ def instructor_dashboard_2(request, course_id):
|
||||
""" Display the instructor dashboard for a course. """
|
||||
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
course = get_course_by_id(course_key, depth=None)
|
||||
is_studio_course = (modulestore().get_modulestore_type(course_key) != ModuleStoreEnum.Type.xml)
|
||||
|
||||
access = {
|
||||
'admin': request.user.is_staff,
|
||||
@@ -67,11 +65,11 @@ def instructor_dashboard_2(request, course_id):
|
||||
raise Http404()
|
||||
|
||||
sections = [
|
||||
_section_course_info(course_key, access),
|
||||
_section_membership(course_key, access),
|
||||
_section_student_admin(course_key, access),
|
||||
_section_data_download(course_key, access),
|
||||
_section_analytics(course_key, access),
|
||||
_section_course_info(course, access),
|
||||
_section_membership(course, access),
|
||||
_section_student_admin(course, access),
|
||||
_section_data_download(course, access),
|
||||
_section_analytics(course, access),
|
||||
]
|
||||
|
||||
#check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
|
||||
@@ -85,19 +83,15 @@ def instructor_dashboard_2(request, course_id):
|
||||
|
||||
# Gate access to course email by feature flag & by course-specific authorization
|
||||
if bulk_email_is_enabled_for_course(course_key):
|
||||
sections.append(_section_send_email(course_key, access, course))
|
||||
sections.append(_section_send_email(course, access))
|
||||
|
||||
# Gate access to Metrics tab by featue flag and staff authorization
|
||||
if settings.FEATURES['CLASS_DASHBOARD'] and access['staff']:
|
||||
sections.append(_section_metrics(course_key, access))
|
||||
sections.append(_section_metrics(course, access))
|
||||
|
||||
# Gate access to Ecommerce tab
|
||||
if course_mode_has_price:
|
||||
sections.append(_section_e_commerce(course_key, access))
|
||||
|
||||
studio_url = None
|
||||
if is_studio_course:
|
||||
studio_url = get_cms_course_link(course)
|
||||
sections.append(_section_e_commerce(course, access))
|
||||
|
||||
enrollment_count = sections[0]['enrollment_count']['total']
|
||||
disable_buttons = False
|
||||
@@ -117,7 +111,7 @@ def instructor_dashboard_2(request, course_id):
|
||||
context = {
|
||||
'course': course,
|
||||
'old_dashboard_url': reverse('instructor_dashboard_legacy', kwargs={'course_id': course_key.to_deprecated_string()}),
|
||||
'studio_url': studio_url,
|
||||
'studio_url': get_studio_url(course, 'course'),
|
||||
'sections': sections,
|
||||
'disable_buttons': disable_buttons,
|
||||
'analytics_dashboard_message': analytics_dashboard_message
|
||||
@@ -139,8 +133,9 @@ section_display_name will be used to generate link titles in the nav bar.
|
||||
""" # pylint: disable=W0105
|
||||
|
||||
|
||||
def _section_e_commerce(course_key, access):
|
||||
def _section_e_commerce(course, access):
|
||||
""" Provide data for the corresponding dashboard section """
|
||||
course_key = course.id
|
||||
coupons = Coupon.objects.filter(course_id=course_key).order_by('-is_active')
|
||||
total_amount = None
|
||||
course_price = None
|
||||
@@ -209,9 +204,9 @@ def set_course_mode_price(request, course_id):
|
||||
return HttpResponse(_("CourseMode price updated successfully"))
|
||||
|
||||
|
||||
def _section_course_info(course_key, access):
|
||||
def _section_course_info(course, access):
|
||||
""" Provide data for the corresponding dashboard section """
|
||||
course = get_course_by_id(course_key, depth=None)
|
||||
course_key = course.id
|
||||
|
||||
section_data = {
|
||||
'section_key': 'course_info',
|
||||
@@ -240,8 +235,9 @@ def _section_course_info(course_key, access):
|
||||
return section_data
|
||||
|
||||
|
||||
def _section_membership(course_key, access):
|
||||
def _section_membership(course, access):
|
||||
""" Provide data for the corresponding dashboard section """
|
||||
course_key = course.id
|
||||
section_data = {
|
||||
'section_key': 'membership',
|
||||
'section_display_name': _('Membership'),
|
||||
@@ -254,12 +250,14 @@ def _section_membership(course_key, access):
|
||||
'list_forum_members_url': reverse('list_forum_members', kwargs={'course_id': course_key.to_deprecated_string()}),
|
||||
'update_forum_role_membership_url': reverse('update_forum_role_membership', kwargs={'course_id': course_key.to_deprecated_string()}),
|
||||
'cohorts_ajax_url': reverse('cohorts', kwargs={'course_key_string': course_key.to_deprecated_string()}),
|
||||
'advanced_settings_url': get_studio_url(course, 'settings/advanced'),
|
||||
}
|
||||
return section_data
|
||||
|
||||
|
||||
def _section_student_admin(course_key, access):
|
||||
def _section_student_admin(course, access):
|
||||
""" Provide data for the corresponding dashboard section """
|
||||
course_key = course.id
|
||||
is_small_course = False
|
||||
enrollment_count = CourseEnrollment.num_enrolled_in(course_key)
|
||||
max_enrollment_for_buttons = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
|
||||
@@ -296,8 +294,9 @@ def _section_extensions(course):
|
||||
return section_data
|
||||
|
||||
|
||||
def _section_data_download(course_key, access):
|
||||
def _section_data_download(course, access):
|
||||
""" Provide data for the corresponding dashboard section """
|
||||
course_key = course.id
|
||||
section_data = {
|
||||
'section_key': 'data_download',
|
||||
'section_display_name': _('Data Download'),
|
||||
@@ -312,8 +311,10 @@ def _section_data_download(course_key, access):
|
||||
return section_data
|
||||
|
||||
|
||||
def _section_send_email(course_key, access, course):
|
||||
def _section_send_email(course, access):
|
||||
""" Provide data for the corresponding bulk email section """
|
||||
course_key = course.id
|
||||
|
||||
# This HtmlDescriptor is only being used to generate a nice text editor.
|
||||
html_module = HtmlDescriptor(
|
||||
course.system,
|
||||
@@ -349,8 +350,9 @@ def _section_send_email(course_key, access, course):
|
||||
return section_data
|
||||
|
||||
|
||||
def _section_analytics(course_key, access):
|
||||
def _section_analytics(course, access):
|
||||
""" Provide data for the corresponding dashboard section """
|
||||
course_key = course.id
|
||||
section_data = {
|
||||
'section_key': 'instructor_analytics',
|
||||
'section_display_name': _('Analytics'),
|
||||
@@ -365,8 +367,9 @@ def _section_analytics(course_key, access):
|
||||
return section_data
|
||||
|
||||
|
||||
def _section_metrics(course_key, access):
|
||||
def _section_metrics(course, access):
|
||||
"""Provide data for the corresponding dashboard section """
|
||||
course_key = course.id
|
||||
section_data = {
|
||||
'section_key': 'metrics',
|
||||
'section_display_name': _('Metrics'),
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
(function(Backbone) {
|
||||
var CohortEditorView = Backbone.View.extend({
|
||||
initialize: function() {
|
||||
initialize: function(options) {
|
||||
this.template = _.template($('#cohort-editor-tpl').text());
|
||||
this.advanced_settings_url = options.advanced_settings_url;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(this.template({
|
||||
cohort: this.model
|
||||
cohort: this.model,
|
||||
advanced_settings_url: this.advanced_settings_url
|
||||
}));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
"change .cohort-select": "showCohortEditor"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
initialize: function(options) {
|
||||
this.template = _.template($('#cohorts-tpl').text());
|
||||
this.advanced_settings_url = options.advanced_settings_url;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -25,7 +26,8 @@
|
||||
var selectedCohort = this.getSelectedCohort();
|
||||
this.editor = new CohortEditorView({
|
||||
el: this.$('.cohort-management-group'),
|
||||
model: selectedCohort
|
||||
model: selectedCohort,
|
||||
advanced_settings_url: this.advanced_settings_url
|
||||
});
|
||||
this.editor.render();
|
||||
}
|
||||
|
||||
@@ -3,4 +3,19 @@
|
||||
<span class="title-value"><%- cohort.get('name') %></span>
|
||||
<span class="group-count"><%- cohort.get('user_count') %></span>
|
||||
</h3>
|
||||
<div class="cohort-management-group-setup">
|
||||
<div class="setup-value">
|
||||
<% if (cohort.get('assignment_type') == "none") { %>
|
||||
<%= gettext("Students are added to this group only when you provide their email addresses or usernames on this page.") %>
|
||||
<% } else { %>
|
||||
<%= gettext("Students are added to this group automatically.") %>
|
||||
<% } %>
|
||||
<a href="http://edx.readthedocs.org" class="incontext-help action-secondary action-help"><%= gettext("What does this mean?") %></a>
|
||||
</div>
|
||||
<div class="setup-actions">
|
||||
<% if (advanced_settings_url != "None") { %>
|
||||
<a href="<%= advanced_settings_url %>" class="action-secondary action-edit"><%= gettext("Edit settings in Studio") %></a>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -221,7 +221,10 @@
|
||||
|
||||
%if course.is_cohorted:
|
||||
<hr class="divider" />
|
||||
<div class="cohort-management membership-section" data-ajax_url="${section_data['cohorts_ajax_url']}">
|
||||
<div class="cohort-management membership-section"
|
||||
data-ajax_url="${section_data['cohorts_ajax_url']}"
|
||||
data-advanced-settings-url="${section_data['advanced_settings_url']}"
|
||||
>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
@@ -234,7 +237,8 @@
|
||||
cohorts.url = cohortManagementElement.data('ajax_url');
|
||||
var cohortsView = new CohortsView({
|
||||
el: cohortManagementElement,
|
||||
model: cohorts
|
||||
model: cohorts,
|
||||
advanced_settings_url: cohortManagementElement.data('advanced-settings-url')
|
||||
});
|
||||
cohortsView.render();
|
||||
cohorts.fetch().done(function() {
|
||||
|
||||
Reference in New Issue
Block a user