Commit 134e764c by sanfordstudent Committed by GitHub

Merge pull request #13447 from edx/sstudent/TNL-5466

bok choy tests for persistent grades
parents bf47486b bf1fcc68
...@@ -1011,6 +1011,7 @@ class StudentAdminPage(PageObject): ...@@ -1011,6 +1011,7 @@ class StudentAdminPage(PageObject):
""" """
url = None url = None
EE_CONTAINER = ".entrance-exam-grade-container" EE_CONTAINER = ".entrance-exam-grade-container"
CS_CONTAINER = ".course-specific-container"
def is_browser_on_page(self): def is_browser_on_page(self):
""" """
...@@ -1026,6 +1027,13 @@ class StudentAdminPage(PageObject): ...@@ -1026,6 +1027,13 @@ class StudentAdminPage(PageObject):
return self.q(css='{} input[name=entrance-exam-student-select-grade]'.format(self.EE_CONTAINER)) return self.q(css='{} input[name=entrance-exam-student-select-grade]'.format(self.EE_CONTAINER))
@property @property
def rescore_problem_input(self):
"""
Returns input box for rescore/reset all on a problem
"""
return self.q(css='{} input[name=problem-select-all]'.format(self.CS_CONTAINER))
@property
def reset_attempts_button(self): def reset_attempts_button(self):
""" """
Returns reset student attempts button. Returns reset student attempts button.
...@@ -1040,6 +1048,20 @@ class StudentAdminPage(PageObject): ...@@ -1040,6 +1048,20 @@ class StudentAdminPage(PageObject):
return self.q(css='{} input[name=rescore-entrance-exam]'.format(self.EE_CONTAINER)) return self.q(css='{} input[name=rescore-entrance-exam]'.format(self.EE_CONTAINER))
@property @property
def rescore_all_submissions_button(self):
"""
Returns rescore student submission button.
"""
return self.q(css='{} input[name=rescore-problem-all]'.format(self.CS_CONTAINER))
@property
def show_background_tasks_button(self):
"""
Return Show Background Tasks button.
"""
return self.q(css='{} input[name=task-history-all]'.format(self.CS_CONTAINER))
@property
def skip_entrance_exam_button(self): def skip_entrance_exam_button(self):
""" """
Return Let Student Skip Entrance Exam button. Return Let Student Skip Entrance Exam button.
...@@ -1115,6 +1137,18 @@ class StudentAdminPage(PageObject): ...@@ -1115,6 +1137,18 @@ class StudentAdminPage(PageObject):
""" """
return self.rescore_submission_button.click() return self.rescore_submission_button.click()
def click_rescore_all_button(self):
"""
clicks rescore all for problem button.
"""
return self.rescore_all_submissions_button.click()
def click_show_background_tasks_button(self):
"""
clicks show background tasks button.
"""
return self.show_background_tasks_button.click()
def click_skip_entrance_exam_button(self): def click_skip_entrance_exam_button(self):
""" """
clicks let student skip entrance exam button. clicks let student skip entrance exam button.
...@@ -1133,12 +1167,19 @@ class StudentAdminPage(PageObject): ...@@ -1133,12 +1167,19 @@ class StudentAdminPage(PageObject):
""" """
return self.background_task_history_button.click() return self.background_task_history_button.click()
def set_student_email(self, email_addres): def set_student_email(self, email_address):
""" """
Sets given email address as value of student email address/username input box. Sets given email address as value of student email address/username input box.
""" """
input_box = self.student_email_input.first.results[0] input_box = self.student_email_input.first.results[0]
input_box.send_keys(email_addres) input_box.send_keys(email_address)
def set_problem_to_rescore(self, problem_locator):
"""
Sets the problem for which to rescore/reset all scores.
"""
input_box = self.rescore_problem_input.first.results[0]
input_box.send_keys(problem_locator)
class CertificatesPage(PageObject): class CertificatesPage(PageObject):
......
...@@ -14,9 +14,12 @@ from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory ...@@ -14,9 +14,12 @@ from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory
from ..helpers import UniqueCourseTest, EventsTestMixin from ..helpers import UniqueCourseTest, EventsTestMixin
from ...pages.studio.auto_auth import AutoAuthPage from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.lms.create_mode import ModeCreationPage from ...pages.lms.create_mode import ModeCreationPage
from ...pages.studio.component_editor import ComponentEditorView
from ...pages.studio.overview import CourseOutlinePage from ...pages.studio.overview import CourseOutlinePage
from ...pages.studio.utils import type_in_codemirror
from ...pages.lms.courseware import CoursewarePage, CoursewareSequentialTabPage from ...pages.lms.courseware import CoursewarePage, CoursewareSequentialTabPage
from ...pages.lms.course_nav import CourseNavPage from ...pages.lms.course_nav import CourseNavPage
from ...pages.lms.instructor_dashboard import InstructorDashboardPage
from ...pages.lms.problem import ProblemPage from ...pages.lms.problem import ProblemPage
from ...pages.common.logout import LogoutPage from ...pages.common.logout import LogoutPage
from ...pages.lms.staff_view import StaffPage from ...pages.lms.staff_view import StaffPage
...@@ -912,16 +915,20 @@ class SubsectionHiddenAfterDueDateTest(UniqueCourseTest): ...@@ -912,16 +915,20 @@ class SubsectionHiddenAfterDueDateTest(UniqueCourseTest):
self.assertEqual(self.progress_page.scores('Test Section 1', 'Test Subsection 1'), [(0, 1)]) self.assertEqual(self.progress_page.scores('Test Section 1', 'Test Subsection 1'), [(0, 1)])
class ProgressPageTest(UniqueCourseTest): class ProgressPageBaseTest(UniqueCourseTest):
""" """
Test that the progress page reports scores from completed assessments. Provides utility methods for tests retrieving
scores from the progress page.
""" """
USERNAME = "STUDENT_TESTER" USERNAME = "STUDENT_TESTER"
EMAIL = "student101@example.com" EMAIL = "student101@example.com"
SECTION_NAME = 'Test Section 1'
SUBSECTION_NAME = 'Test Subsection 1'
UNIT_NAME = 'Test Unit 1'
PROBLEM_NAME = 'Test Problem 1'
def setUp(self): def setUp(self):
super(ProgressPageTest, self).setUp() super(ProgressPageBaseTest, self).setUp()
self.courseware_page = CoursewarePage(self.browser, self.course_id) self.courseware_page = CoursewarePage(self.browser, self.course_id)
self.problem_page = ProblemPage(self.browser) # pylint: disable=attribute-defined-outside-init self.problem_page = ProblemPage(self.browser) # pylint: disable=attribute-defined-outside-init
self.progress_page = ProgressPage(self.browser, self.course_id) self.progress_page = ProgressPage(self.browser, self.course_id)
...@@ -943,9 +950,11 @@ class ProgressPageTest(UniqueCourseTest): ...@@ -943,9 +950,11 @@ class ProgressPageTest(UniqueCourseTest):
) )
course_fix.add_children( course_fix.add_children(
XBlockFixtureDesc('chapter', 'Test Section 1').add_children( XBlockFixtureDesc('chapter', self.SECTION_NAME).add_children(
XBlockFixtureDesc('sequential', 'Test Subsection 1').add_children( XBlockFixtureDesc('sequential', self.SUBSECTION_NAME).add_children(
create_multiple_choice_problem('Test Problem 1') XBlockFixtureDesc('vertical', self.UNIT_NAME).add_children(
create_multiple_choice_problem(self.PROBLEM_NAME)
)
) )
) )
).install() ).install()
...@@ -953,15 +962,6 @@ class ProgressPageTest(UniqueCourseTest): ...@@ -953,15 +962,6 @@ class ProgressPageTest(UniqueCourseTest):
# Auto-auth register for the course. # Auto-auth register for the course.
_auto_auth(self.browser, self.USERNAME, self.EMAIL, False, self.course_id) _auto_auth(self.browser, self.USERNAME, self.EMAIL, False, self.course_id)
def test_progress_page_shows_scored_problems(self):
with self._logged_in_session():
self.assertEqual(self._get_scores(), [(0, 1)])
self.assertEqual(self._get_section_score(), (0, 1))
self.courseware_page.visit()
self._answer_problem_correctly()
self.assertEqual(self._get_scores(), [(1, 1)])
self.assertEqual(self._get_section_score(), (1, 1))
def _answer_problem_correctly(self): def _answer_problem_correctly(self):
""" """
Submit a correct answer to the problem. Submit a correct answer to the problem.
...@@ -975,24 +975,156 @@ class ProgressPageTest(UniqueCourseTest): ...@@ -975,24 +975,156 @@ class ProgressPageTest(UniqueCourseTest):
Return a list of scores from the progress page. Return a list of scores from the progress page.
""" """
self.progress_page.visit() self.progress_page.visit()
return self.progress_page.section_score('Test Section 1', 'Test Subsection 1') return self.progress_page.section_score(self.SECTION_NAME, self.SUBSECTION_NAME)
def _get_scores(self): def _get_scores(self):
""" """
Return a list of scores from the progress page. Return a list of scores from the progress page.
""" """
self.progress_page.visit() self.progress_page.visit()
return self.progress_page.scores('Test Section 1', 'Test Subsection 1') return self.progress_page.scores(self.SECTION_NAME, self.SUBSECTION_NAME)
@contextmanager @contextmanager
def _logged_in_session(self): def _logged_in_session(self, staff=False):
""" """
Ensure that the user is logged in and out appropriately at the beginning Ensure that the user is logged in and out appropriately at the beginning
and end of the current test. and end of the current test.
""" """
self.logout_page.visit() self.logout_page.visit()
try: try:
_auto_auth(self.browser, self.USERNAME, self.EMAIL, False, self.course_id) if staff:
_auto_auth(self.browser, "STAFF_TESTER", "staff101@example.com", True, self.course_id)
else:
_auto_auth(self.browser, self.USERNAME, self.EMAIL, False, self.course_id)
yield yield
finally: finally:
self.logout_page.visit() self.logout_page.visit()
class ProgressPageTest(ProgressPageBaseTest):
"""
Test that the progress page reports scores from completed assessments.
"""
def test_progress_page_shows_scored_problems(self):
with self._logged_in_session():
self.assertEqual(self._get_scores(), [(0, 1)])
self.assertEqual(self._get_section_score(), (0, 1))
self.courseware_page.visit()
self._answer_problem_correctly()
self.assertEqual(self._get_scores(), [(1, 1)])
self.assertEqual(self._get_section_score(), (1, 1))
@ddt.ddt
class PersistentGradesTest(ProgressPageBaseTest):
"""
Test that grades for completed assessments are persisted
when various edits are made.
"""
def setUp(self):
super(PersistentGradesTest, self).setUp()
self.instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
def _change_subsection_structure(self):
"""
Adds a unit to the subsection, which
should not affect a persisted subsectiong grade.
"""
with self._logged_in_session(staff=True):
self.course_outline.visit()
subsection = self.course_outline.section(self.SECTION_NAME).subsection(self.SUBSECTION_NAME)
subsection.expand_subsection()
subsection.add_unit()
def _set_staff_lock_on_subsection(self, locked):
"""
Sets staff lock for a subsection, which should hide the
subsection score from students on the progress page.
"""
with self._logged_in_session(staff=True):
self.course_outline.visit()
subsection = self.course_outline.section_at(0).subsection_at(0)
subsection.set_staff_lock(locked)
self.assertEqual(subsection.has_staff_lock_warning, locked)
def _change_weight_for_problem(self):
"""
Changes the weight of the problem, which should not affect
persisted grades.
"""
with self._logged_in_session(staff=True):
self.course_outline.visit()
self.course_outline.section_at(0).subsection_at(0).expand_subsection()
unit = self.course_outline.section_at(0).subsection_at(0).unit(self.UNIT_NAME).go_to()
container = unit.xblocks[0].go_to_container()
component = container.xblocks[0].children[0]
component.edit()
component_editor = ComponentEditorView(self.browser, component.locator)
component_editor.set_field_value_and_save('Problem Weight', 5)
def _rescore_for_all(self):
"""
Triggers a rescore for all students. Currently unimplemented.
"""
pass
def _edit_problem_content(self):
"""
Replaces the content of a problem with other html.
Should not affect persisted grades.
"""
with self._logged_in_session(staff=True):
self.course_outline.visit()
self.course_outline.section_at(0).subsection_at(0).expand_subsection()
unit = self.course_outline.section_at(0).subsection_at(0).unit(self.UNIT_NAME).go_to()
component = unit.xblocks[1]
edit_view = component.edit()
modified_content = "<p>modified content</p>"
# Set content in the CodeMirror editor.
type_in_codemirror(self, 0, modified_content)
edit_view.q(css='.action-save').click()
@ddt.data(
_edit_problem_content,
_change_subsection_structure,
_change_weight_for_problem,
_rescore_for_all
)
def test_content_changes_do_not_change_score(self, edit):
with self._logged_in_session():
self.assertEqual(self._get_scores(), [(0, 1)])
self.assertEqual(self._get_section_score(), (0, 1))
self.courseware_page.visit()
self._answer_problem_correctly()
self.assertEqual(self._get_scores(), [(1, 1)])
self.assertEqual(self._get_section_score(), (1, 1))
edit(self)
with self._logged_in_session():
self.assertEqual(self._get_scores(), [(1, 1)])
self.assertEqual(self._get_section_score(), (1, 1))
def test_visibility_change_does_affect_score(self):
with self._logged_in_session():
self.assertEqual(self._get_scores(), [(0, 1)])
self.assertEqual(self._get_section_score(), (0, 1))
self.courseware_page.visit()
self._answer_problem_correctly()
self.assertEqual(self._get_scores(), [(1, 1)])
self.assertEqual(self._get_section_score(), (1, 1))
self._set_staff_lock_on_subsection(True)
with self._logged_in_session():
self.assertEqual(self._get_scores(), None)
self.assertEqual(self._get_section_score(), None)
self._set_staff_lock_on_subsection(False)
with self._logged_in_session():
self.assertEqual(self._get_scores(), [(1, 1)])
self.assertEqual(self._get_section_score(), (1, 1))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment