Support staff locking on the unit page

STUD-1873
This commit is contained in:
cahrens
2014-07-10 11:33:49 -04:00
parent cf70eb6e2a
commit d447c07540
23 changed files with 926 additions and 424 deletions

View File

@@ -10,16 +10,24 @@ class StaffPage(PageObject):
"""
url = None
STAFF_STATUS_CSS = '#staffstatus'
def is_browser_on_page(self):
return self.q(css='#staffstatus').present
return self.q(css=self.STAFF_STATUS_CSS).present
@property
def staff_status(self):
"""
Return the current status, either Staff view or Student view
"""
return self.q(css='#staffstatus').text[0]
return self.q(css=self.STAFF_STATUS_CSS).text[0]
def toggle_staff_view(self):
"""
Toggle between staff view and student view.
"""
self.q(css=self.STAFF_STATUS_CSS).first.click()
self.wait_for_ajax()
def open_staff_debug_info(self):
"""

View File

@@ -81,6 +81,33 @@ class ContainerPage(PageObject):
"""
return self.q(css='.pub-status').first.text[0]
@property
def release_title(self):
"""
Returns the title before the release date in the publishing sidebar component.
"""
return self.q(css='.wrapper-release .title').first.text[0]
@property
def release_date(self):
"""
Returns the release date of the unit (with ancestor inherited from), as displayed
in the publishing sidebar component.
"""
return self.q(css='.wrapper-release .copy').first.text[0]
@property
def currently_visible_to_students(self):
"""
Returns True if the unit is marked as currently visible to students
(meaning that a warning is being displayed).
"""
warnings = self.q(css='.container-message .warning')
if not warnings.is_present():
return False
warning_text = warnings.first.text[0]
return warning_text == "This content is live for students. Edit with caution."
@property
def publish_action(self):
"""
@@ -96,6 +123,22 @@ class ContainerPage(PageObject):
self.q(css='a.button.action-primary').first.click()
self.wait_for_ajax()
def toggle_staff_lock(self):
"""
Toggles "hide from students" which enables or disables a staff-only lock.
Returns True if the lock is now enabled, else False.
"""
class_attribute_values = self.q(css='a.action-staff-lock>i').attrs('class')
was_locked_initially = 'icon-check' in class_attribute_values
if not was_locked_initially:
self.q(css='a.action-staff-lock').first.click()
else:
click_css(self, 'a.action-staff-lock', 0, require_notification=False)
self.q(css='a.button.action-primary').first.click()
self.wait_for_ajax()
return not was_locked_initially
def view_published_version(self):
"""
Clicks "View Published Version", which will open the published version of the unit page in the LMS.

View File

@@ -16,6 +16,7 @@ from ..pages.lms.progress import ProgressPage
from ..pages.lms.dashboard import DashboardPage
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
@@ -421,3 +422,87 @@ class XBlockAcidChildTest(XBlockAcidBase):
@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.
"""
def setUp(self):
super(VisibleToStaffOnlyTest, self).setUp()
course_fix = CourseFixture(
self.course_info['org'],
self.course_info['number'],
self.course_info['run'],
self.course_info['display_name']
)
course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children(
XBlockFixtureDesc('sequential', 'Subsection With Locked Unit').add_children(
XBlockFixtureDesc('vertical', 'Locked Unit', metadata={'visible_to_staff_only': True}).add_children(
XBlockFixtureDesc('html', 'Html Child in locked unit', data="<html>Visible only to staff</html>"),
),
XBlockFixtureDesc('vertical', 'Unlocked Unit').add_children(
XBlockFixtureDesc('html', 'Html Child in unlocked unit', data="<html>Visible only to all</html>"),
)
),
XBlockFixtureDesc('sequential', 'Unlocked Subsection').add_children(
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc('html', 'Html Child in visible unit', data="<html>Visible to all</html>"),
)
),
XBlockFixtureDesc('sequential', 'Locked Subsection', metadata={'visible_to_staff_only': True}).add_children(
XBlockFixtureDesc('vertical', 'Test Unit').add_children(
XBlockFixtureDesc(
'html', 'Html Child in locked subsection', data="<html>Visible only to staff</html>"
)
)
)
)
).install()
self.courseware_page = CoursewarePage(self.browser, self.course_id)
self.course_nav = CourseNavPage(self.browser)
def test_visible_to_staff(self):
"""
Scenario: All content is visible for a user marked is_staff (different from course staff)
Given some of the course content has been marked 'visible_to_staff_only'
And I am logged on with an account marked 'is_staff'
Then I can see all course content
"""
AutoAuthPage(self.browser, username="STAFF_TESTER", email="johndoe_staff@example.com",
course_id=self.course_id, staff=True).visit()
self.courseware_page.visit()
self.assertEqual(3, len(self.course_nav.sections['Test Section']))
self.course_nav.go_to_section("Test Section", "Subsection With Locked Unit")
self.assertEqual(["Html Child in locked unit", "Html Child in unlocked unit"], self.course_nav.sequence_items)
self.course_nav.go_to_section("Test Section", "Unlocked Subsection")
self.assertEqual(["Html Child in visible unit"], self.course_nav.sequence_items)
self.course_nav.go_to_section("Test Section", "Locked Subsection")
self.assertEqual(["Html Child in locked subsection"], self.course_nav.sequence_items)
def test_visible_to_student(self):
"""
Scenario: Content marked 'visible_to_staff_only' is not visible for students in the course
Given some of the course content has been marked 'visible_to_staff_only'
And I am logged on with an authorized student account
Then I can only see content without 'visible_to_staff_only' set to True
"""
AutoAuthPage(self.browser, username="STUDENT_TESTER", email="johndoe_student@example.com",
course_id=self.course_id, staff=False).visit()
self.courseware_page.visit()
self.assertEqual(2, len(self.course_nav.sections['Test Section']))
self.course_nav.go_to_section("Test Section", "Subsection With Locked Unit")
self.assertEqual(["Html Child in unlocked unit"], self.course_nav.sequence_items)
self.course_nav.go_to_section("Test Section", "Unlocked Subsection")
self.assertEqual(["Html Child in visible unit"], self.course_nav.sequence_items)

View File

@@ -11,9 +11,12 @@ from ..fixtures.course import XBlockFixtureDesc
from ..pages.studio.component_editor import ComponentEditorView
from ..pages.studio.utils import add_discussion
from ..pages.lms.courseware import CoursewarePage
from ..pages.lms.staff_view import StaffPage
from unittest import skip
from acceptance.tests.base_studio_test import StudioCourseTest
import datetime
from bok_choy.promise import Promise
@attr('shard_1')
@@ -46,15 +49,15 @@ class ContainerBase(StudioCourseTest):
container = unit.xblocks[1].go_to_container()
return container
def go_to_unit_page(self):
def go_to_unit_page(self, section_name='Test Section', subsection_name='Test Subsection', unit_name='Test Unit'):
"""
Go to the test unit page.
If make_draft is true, the unit page will be put into draft mode.
"""
self.outline.visit()
subsection = self.outline.section('Test Section').subsection('Test Subsection')
return subsection.toggle_expand().unit('Test Unit').go_to()
subsection = self.outline.section(section_name).subsection(subsection_name)
return subsection.toggle_expand().unit(unit_name).go_to()
def verify_ordering(self, container, expected_orderings):
"""
@@ -379,6 +382,8 @@ class UnitPublishingTest(ContainerBase):
PUBLISHED_STATUS = "Publishing Status\nPublished"
DRAFT_STATUS = "Publishing Status\nDraft (Unpublished changes)"
LOCKED_STATUS = "Publishing Status\nUnpublished (Staff only)"
RELEASE_TITLE_RELEASED = "RELEASED:"
def setup_fixtures(self):
"""
@@ -393,6 +398,8 @@ class UnitPublishingTest(ContainerBase):
self.course_info['run'],
self.course_info['display_name']
)
past_start_date = datetime.datetime(1974, 6, 22)
self.past_start_date_text = "Jun 22, 1974 at 00:00 UTC"
course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section').add_children(
@@ -401,6 +408,20 @@ class UnitPublishingTest(ContainerBase):
XBlockFixtureDesc('html', 'Test html', data=self.html_content)
)
)
),
XBlockFixtureDesc('chapter', 'Unlocked Section', metadata={'start': past_start_date.isoformat()}).add_children(
XBlockFixtureDesc('sequential', 'Unlocked Subsection').add_children(
XBlockFixtureDesc('vertical', 'Unlocked Unit').add_children(
XBlockFixtureDesc('problem', '<problem></problem>', data=self.html_content)
)
)
),
XBlockFixtureDesc('chapter', 'Section With Locked Unit').add_children(
XBlockFixtureDesc('sequential', 'Subsection With Locked Unit', metadata={'start': past_start_date.isoformat()}).add_children(
XBlockFixtureDesc('vertical', 'Locked Unit', metadata={'visible_to_staff_only': True}).add_children(
XBlockFixtureDesc('discussion', '', data=self.html_content)
)
)
)
).install()
@@ -408,61 +429,220 @@ class UnitPublishingTest(ContainerBase):
def test_publishing(self):
"""
Test the state changes when a published unit has draft changes.
Scenario: The publish title changes based on whether or not draft content exists
Given I have a published unit with no unpublished changes
When I go to the unit page in Studio
Then the title in the Publish information box is "Published"
And the Publish button is disabled
And when I add a component to the unit
Then the title in the Publish information box is "Draft (Unpublished changes)"
And the Publish button is enabled
And when I click the Publish button
Then the title in the Publish information box is "Published"
"""
unit = self.go_to_unit_page()
self.assertEqual(self.PUBLISHED_STATUS, unit.publish_title)
self._verify_publish_title(unit, self.PUBLISHED_STATUS)
# Start date set in course fixture to 1970.
self._verify_release_date_info(
unit, self.RELEASE_TITLE_RELEASED, 'Jan 01, 1970 at 00:00 UTC with Section "Test Section"'
)
# Should not be able to click on Publish action -- but I don't know how to test that it is not clickable.
# TODO: continue discussion with Muhammad and Jay about this.
# Add a component to the page so it will have unpublished changes.
add_discussion(unit)
self.assertEqual(self.DRAFT_STATUS, unit.publish_title)
self._verify_publish_title(unit, self.DRAFT_STATUS)
unit.publish_action.click()
unit.wait_for_ajax()
self.assertEqual(self.PUBLISHED_STATUS, unit.publish_title)
self._verify_publish_title(unit, self.PUBLISHED_STATUS)
def test_discard_changes(self):
"""
Test the state after discard changes.
Scenario: The publish title changes after "Discard Changes" is clicked
Given I have a published unit with no unpublished changes
When I go to the unit page in Studio
Then the Discard Changes button is disabled
And I add a component to the unit
Then the title in the Publish information box is "Draft (Unpublished changes)"
And the Discard Changes button is enabled
And when I click the Discard Changes button
Then the title in the Publish information box is "Published"
"""
unit = self.go_to_unit_page()
add_discussion(unit)
self.assertEqual(self.DRAFT_STATUS, unit.publish_title)
self._verify_publish_title(unit, self.DRAFT_STATUS)
unit.discard_changes()
self.assertEqual(self.PUBLISHED_STATUS, unit.publish_title)
self._verify_publish_title(unit, self.PUBLISHED_STATUS)
def test_view_live_no_changes(self):
"""
Tests viewing of live with initial published content.
Scenario: "View Live" shows published content in LMS
Given I have a published unit with no unpublished changes
When I go to the unit page in Studio
Then the View Live button is enabled
And when I click on the View Live button
Then I see the published content in LMS
"""
unit = self.go_to_unit_page()
unit.view_published_version()
self.assertEqual(1, self.courseware.num_xblock_components)
self.assertEqual('html', self.courseware.xblock_component_type(0))
self._verify_components_visible(['html'])
def test_view_live_changes(self):
"""
Tests that viewing of live with draft content does not show the draft content.
Scenario: "View Live" does not show draft content in LMS
Given I have a published unit with no unpublished changes
When I go to the unit page in Studio
And when I add a component to the unit
And when I click on the View Live button
Then I see the published content in LMS
And I do not see the unpublished component
"""
unit = self.go_to_unit_page()
add_discussion(unit)
unit.view_published_version()
self.assertEqual(1, self.courseware.num_xblock_components)
self.assertEqual('html', self.courseware.xblock_component_type(0))
self._verify_components_visible(['html'])
self.assertEqual(self.html_content, self.courseware.xblock_component_html_content(0))
def test_view_live_after_publish(self):
"""
Tests viewing of live after creating draft and publishing it.
Scenario: "View Live" shows newly published content
Given I have a published unit with no unpublished changes
When I go to the unit page in Studio
And when I add a component to the unit
And when I click the Publish button
And when I click on the View Live button
Then I see the newly published component
"""
unit = self.go_to_unit_page()
add_discussion(unit)
unit.publish_action.click()
unit.view_published_version()
self.assertEqual(2, self.courseware.num_xblock_components)
self.assertEqual('html', self.courseware.xblock_component_type(0))
self.assertEqual('discussion', self.courseware.xblock_component_type(1))
self._verify_components_visible(['html', 'discussion'])
def test_initially_unlocked_visible_to_students(self):
"""
Scenario: An unlocked unit with release date in the past is visible to students
Given I have a published unlocked unit with release date in the past
When I go to the unit page in Studio
Then the unit has a warning that it is visible to students
And it is marked as "RELEASED" with release date in the past visible
And when I click on the View Live Button
And when I view the course as a student
Then I see the content in the unit
"""
unit = self.go_to_unit_page("Unlocked Section", "Unlocked Subsection", "Unlocked Unit")
self._verify_publish_title(unit, self.PUBLISHED_STATUS)
self.assertTrue(unit.currently_visible_to_students)
self._verify_release_date_info(
unit, self.RELEASE_TITLE_RELEASED, self.past_start_date_text + ' with Section "Unlocked Section"'
)
unit.view_published_version()
self._verify_student_view_visible(['problem'])
def test_locked_visible_to_staff_only(self):
"""
Scenario: After locking a unit with release date in the past, it is only visible to staff
Given I have a published unlocked unit with release date in the past
When I go to the unit page in Studio
And when I select "Hide from students"
Then the unit does not have a warning that it is visible to students
And when I click on the View Live Button
Then I see the content in the unit when logged in as staff
And when I view the course as a student
Then I do not see any content in the unit
"""
unit = self.go_to_unit_page("Unlocked Section", "Unlocked Subsection", "Unlocked Unit")
checked = unit.toggle_staff_lock()
self.assertTrue(checked)
self.assertFalse(unit.currently_visible_to_students)
self._verify_publish_title(unit, self.LOCKED_STATUS)
unit.view_published_version()
# Will initially be in staff view, locked component should be visible.
self._verify_components_visible(['problem'])
# Switch to student view and verify not visible
self._verify_student_view_locked()
def test_initially_locked_not_visible_to_students(self):
"""
Scenario: A locked unit with release date in the past is not visible to students
Given I have a published locked unit with release date in the past
When I go to the unit page in Studio
Then the unit does not have a warning that it is visible to students
And it is marked as "RELEASED" with release date in the past visible
And when I click on the View Live Button
And when I view the course as a student
Then I do not see any content in the unit
"""
unit = self.go_to_unit_page("Section With Locked Unit", "Subsection With Locked Unit", "Locked Unit")
self._verify_publish_title(unit, self.LOCKED_STATUS)
self.assertFalse(unit.currently_visible_to_students)
self._verify_release_date_info(
unit, self.RELEASE_TITLE_RELEASED,
self.past_start_date_text + ' with Subsection "Subsection With Locked Unit"'
)
unit.view_published_version()
self._verify_student_view_locked()
def test_unlocked_visible_to_all(self):
"""
Scenario: After unlocking a unit with release date in the past, it is visible to both students and staff
Given I have a published unlocked unit with release date in the past
When I go to the unit page in Studio
And when I deselect "Hide from students"
Then the unit does have a warning that it is visible to students
And when I click on the View Live Button
Then I see the content in the unit when logged in as staff
And when I view the course as a student
Then I see the content in the unit
"""
unit = self.go_to_unit_page("Section With Locked Unit", "Subsection With Locked Unit", "Locked Unit")
checked = unit.toggle_staff_lock()
self.assertFalse(checked)
self._verify_publish_title(unit, self.PUBLISHED_STATUS)
self.assertTrue(unit.currently_visible_to_students)
unit.view_published_version()
# Will initially be in staff view, components always visible.
self._verify_components_visible(['discussion'])
# Switch to student view and verify visible.
self._verify_student_view_visible(['discussion'])
def _verify_student_view_locked(self):
"""
Verifies no component is visible when viewing as a student.
"""
StaffPage(self.browser).toggle_staff_view()
self.assertEqual(0, self.courseware.num_xblock_components)
def _verify_student_view_visible(self, expected_components):
"""
Verifies expected components are visible when viewing as a student.
"""
StaffPage(self.browser).toggle_staff_view()
self._verify_components_visible(expected_components)
def _verify_components_visible(self, expected_components):
"""
Verifies the expected components are visible (and there are no extras).
"""
self.assertEqual(len(expected_components), self.courseware.num_xblock_components)
for index, component in enumerate(expected_components):
self.assertEqual(component, self.courseware.xblock_component_type(index))
def _verify_release_date_info(self, unit, expected_title, expected_date):
"""
Verifies how the release date is displayed in the publishing sidebar.
"""
self.assertEqual(expected_title, unit.release_title)
self.assertEqual(expected_date, unit.release_date)
def _verify_publish_title(self, unit, expected_title):
"""
Waits for the publish title to change to the expected value.
"""
def wait_for_title_change():
return (unit.publish_title == expected_title, unit.publish_title)
Promise(wait_for_title_change, "Publish title incorrect. Found '" + unit.publish_title + "'").fulfill()
# TODO: need to work with Jay/Christine to get testing of "Preview" working.
# def test_preview(self):