Commit 665020d0 by cahrens Committed by Andy Armstrong

Add acceptance and a11y tests for regrading UI

parent 5a530dab
......@@ -110,6 +110,7 @@ class StaffAreaA11yTest(OpenAssessmentA11yTest):
# Click on staff tools and search for the user.
self.staff_area_page.show_learner(username)
self.staff_area_page.expand_learner_report_sections()
self._check_a11y(self.staff_area_page)
......
......@@ -32,6 +32,14 @@ class OpenAssessmentPage(PageObject):
super(OpenAssessmentPage, self).__init__(browser)
self._problem_location = problem_location
def _bounded_selector(self, selector):
"""
Allows scoping to a portion of the page.
The default implementation just returns the selector
"""
return selector
@property
def url(self):
return "{base}/{loc}".format(
......@@ -39,19 +47,19 @@ class OpenAssessmentPage(PageObject):
loc=self._problem_location
)
def submit(self):
def submit(self, button_css=".action--submit"):
"""
Click the submit button on the page.
This relies on the fact that we use the same CSS styles for submit buttons
in all problem steps.
in all problem steps (unless custom value for button_css is passed in).
"""
EmptyPromise(
lambda: 'is--disabled' not in " ".join(self.q(css=".action--submit").attrs('class')),
lambda: 'is--disabled' not in " ".join(self.q(css=self._bounded_selector(button_css)).attrs('class')),
"Submit button is enabled."
).fulfill()
with self.handle_alert():
self.q(css=".action--submit").first.click()
self.q(css=self._bounded_selector(button_css)).first.click()
def hide_django_debug_tool(self):
if self.q(css='#djDebug').visible:
......@@ -155,7 +163,42 @@ class SubmissionPage(OpenAssessmentPage):
return self.q(css="#submission__custom__upload").visible
class AssessmentPage(OpenAssessmentPage):
class AssessmentMixin(object):
"""
Mixin for interacting with the assessment rubric.
"""
def assess(self, options_selected):
"""
Create an assessment.
Args:
options_selected (list of int): list of the indices (starting from 0)
of each option to select in the rubric.
Returns:
AssessmentPage
Example usage:
>>> page.assess([0, 2, 1])
"""
for criterion_num, option_num in enumerate(options_selected):
sel = "#assessment__rubric__question--{criterion_num}__{option_num}".format(
criterion_num=criterion_num,
option_num=option_num
)
self.q(css=self._bounded_selector(sel)).first.click()
self.submit_assessment()
return self
def submit_assessment(self):
"""
Submit an assessment of the problem.
"""
self.submit()
class AssessmentPage(OpenAssessmentPage, AssessmentMixin):
"""
Page object representing an "assessment" step in an ORA problem.
"""
......@@ -193,30 +236,6 @@ class AssessmentPage(OpenAssessmentPage):
# self.wait_for_element_visibility(".chapter.is-open", "Chapter heading is on visible", timeout=10)
return self.q(css=".chapter.is-open").visible
def assess(self, options_selected):
"""
Create an assessment.
Args:
options_selected (list of int): list of the indices (starting from 0)
of each option to select in the rubric.
Returns:
AssessmentPage
Example usage:
>>> page.assess([0, 2, 1])
"""
for criterion_num, option_num in enumerate(options_selected):
sel = "#assessment__rubric__question--{criterion_num}__{option_num}".format(
criterion_num=criterion_num,
option_num=option_num
)
self.q(css=sel).first.click()
self.submit()
return self
@property
def response_text(self):
"""
......@@ -341,11 +360,17 @@ class GradePage(OpenAssessmentPage):
return score_candidates[0] if len(score_candidates) > 0 else None
class StaffAreaPage(OpenAssessmentPage):
class StaffAreaPage(OpenAssessmentPage, AssessmentMixin):
"""
Page object representing the tabbed staff area.
"""
def _bounded_selector(self, selector):
"""
Return `selector`, but limited to the staff area management area.
"""
return '.openassessment__staff-area {}'.format(selector)
def is_browser_on_page(self):
return self.q(css=".openassessment__staff-area").is_present()
......@@ -354,7 +379,7 @@ class StaffAreaPage(OpenAssessmentPage):
"""
Returns the names of the selected toolbar buttons.
"""
buttons = self.q(css=".ui-staff__button")
buttons = self.q(css=self._bounded_selector(".ui-staff__button"))
return [button.text for button in buttons if u'is--active' in button.get_attribute('class')]
@property
......@@ -362,7 +387,7 @@ class StaffAreaPage(OpenAssessmentPage):
"""
Returns the classes of the visible staff panels
"""
panels = self.q(css=".wrapper--ui-staff")
panels = self.q(css=self._bounded_selector(".wrapper--ui-staff"))
return [panel.get_attribute('class') for panel in panels if u'is--hidden' not in panel.get_attribute('class')]
def click_staff_toolbar_button(self, button_name):
......@@ -370,7 +395,7 @@ class StaffAreaPage(OpenAssessmentPage):
Presses the button to show the panel with the specified name.
:return:
"""
buttons = self.q(css=".button-{button_name}".format(button_name=button_name))
buttons = self.q(css=self._bounded_selector(".button-{button_name}".format(button_name=button_name)))
buttons.first.click()
def click_staff_panel_close_button(self, panel_name):
......@@ -378,16 +403,19 @@ class StaffAreaPage(OpenAssessmentPage):
Presses the close button on the staff panel with the specified name.
:return:
"""
self.q(css=".wrapper--{panel_name} .ui-staff_close_button".format(panel_name=panel_name)).click()
self.q(
css=self._bounded_selector(".wrapper--{panel_name} .ui-staff_close_button".format(panel_name=panel_name))
).click()
def show_learner(self, username):
"""
Clicks the staff tools panel and and searches for learner information about the given username.
"""
self.click_staff_toolbar_button("staff-tools")
self.wait_for_element_visibility("input.openassessment__student_username", "Input is present")
self.q(css="input.openassessment__student_username").fill(username)
submit_button = self.q(css=".action--submit-username")
student_input_css = self._bounded_selector("input.openassessment__student_username")
self.wait_for_element_visibility(student_input_css, "Input is present")
self.q(css=student_input_css).fill(username)
submit_button = self.q(css=self._bounded_selector(".action--submit-username"))
submit_button.first.click()
self.wait_for_element_visibility(".staff-info__student__report", "Student report is present")
......@@ -396,12 +424,77 @@ class StaffAreaPage(OpenAssessmentPage):
"""
Returns the text present in the learner report (useful for case where there is no response).
"""
return self.q(css=".staff-info__student__report").text[0]
return self.q(css=self._bounded_selector(".staff-info__student__report")).text[0]
def verify_learner_report_text(self, expectedText):
"""
Verifies the learner report text is as expected.
"""
EmptyPromise(
lambda: self.learner_report_text == expectedText,
"Learner report text correct"
).fulfill()
@property
def learner_report_sections(self):
"""
Returns the titles of the collapsible learner report sections present on the page.
"""
sections = self.q(css=".ui-staff__subtitle")
self.wait_for_section_titles()
sections = self.q(css=self._bounded_selector(".ui-staff__subtitle"))
return [section.text for section in sections]
def wait_for_section_titles(self):
"""
Wait for section titles to appear.
"""
EmptyPromise(
lambda: len(self.q(css=self._bounded_selector(".ui-staff__subtitle"))) > 0,
"Section titles appeared"
).fulfill()
def expand_learner_report_sections(self):
"""
Expands all the sections in the learner report.
"""
self.wait_for_section_titles()
self.q(css=self._bounded_selector(".ui-staff__subtitle")).click()
@property
def learner_final_score(self):
"""
Returns the final score displayed in the learner report.
"""
score = self.q(css=self._bounded_selector(".staff-info__student__grade .ui-toggle-visibility__content"))
if len(score) == 0:
return None
return score.text[0]
def verify_learner_final_score(self, expected_score):
"""
Verifies that the final score in the learner report is equal to the expected value.
"""
EmptyPromise(
lambda: self.learner_final_score == expected_score,
"Learner score is updated"
).fulfill()
@property
def learner_response(self):
return self.q(
css=self._bounded_selector(".staff-info__student__response .ui-toggle-visibility__content")
).text[0]
def submit_assessment(self):
"""
Submit a staff assessment of the problem.
"""
self.submit(button_css=".wrapper--staff-assessment .action--submit")
def cancel_submission(self):
"""
Cancel a learner's assessment.
"""
# Must put a comment to enable the submit button.
self.q(css=self._bounded_selector("textarea.cancel_submission_comments")).fill("comment")
self.submit(button_css=".action--submit-cancel-submission")
......@@ -314,13 +314,14 @@ class StaffAreaTest(OpenAssessmentTest):
# Click on staff tools and search for user
self.staff_area_page.show_learner(username)
self.assertNotIn('A response was not found for this learner', self.staff_area_page.learner_report_text)
self.assertEqual(
[u'Learner Response', u"Learner's Self Assessment", u"Learner's Final Grade"],
[u'Learner Response', u"Learner's Self Assessment", u"Learner's Final Grade",
u"Submit Assessment Grade Override", u"Remove Submission From Peer Grading"],
self.staff_area_page.learner_report_sections
)
self.assertNotIn('A response was not found for this learner', self.staff_area_page.learner_report_text)
@retry()
@attr('acceptance')
def test_student_info_no_submission(self):
......@@ -338,9 +339,79 @@ class StaffAreaTest(OpenAssessmentTest):
# Click on staff tools and search for user
self.staff_area_page.show_learner('no-submission-learner')
self.staff_area_page.verify_learner_report_text('A response was not found for this learner.')
@retry()
@attr('acceptance')
def test_staff_override(self):
"""
Scenario: staff can override a learner's grade
Given I am viewing the staff area of an ORA problem
When I search for a learner in staff tools
And the learner has submitted a response to an ORA problem with self-assessment
Then I can submit a staff override of the self-assessment
And I see the updated final score
"""
username = self.do_self_assessment()
self.staff_area_page.visit()
# Click on staff tools and search for user
self.staff_area_page.show_learner(username)
# Check the learner's current score.
self.staff_area_page.expand_learner_report_sections()
self.staff_area_page.verify_learner_final_score("Final grade: 6 out of 8")
# Do staff override and wait for final score to change.
self.staff_area_page.assess([0, 1])
# Verify that the new student score is different from the original one.
# TODO: uncomment this after hooked up to the API. Also verify other state if appropriate.
# self.staff_area_page.verify_learner_final_score("Final grade: 1 out of 8")
@retry()
@attr('acceptance')
def test_cancel_submission(self):
"""
Scenario: staff can cancel a learner's submission
Given I am viewing the staff area of an ORA problem
When I search for a learner in staff tools
And the learner has submitted a response to an ORA problem with self-assessment
Then I can cancel the learner's submission
And I see an updated message indicating that the submission has been canceled.
"""
username = self.do_self_assessment()
self.staff_area_page.visit()
# Click on staff tools and search for user
self.staff_area_page.show_learner(username)
# Check the learner's current score.
self.staff_area_page.expand_learner_report_sections()
self.staff_area_page.verify_learner_final_score("Final grade: 6 out of 8")
# Cancel the student submission
self.staff_area_page.cancel_submission()
self.staff_area_page.verify_learner_final_score(
"The learner's submission has been removed from peer assessment. "
"The learner receives a grade of zero unless you reset the learner's attempts for the "
"problem to allow them to resubmit a response."
)
# Verify that the staff override and submission removal sections are now gone.
self.assertEqual(
[u'Learner Response', u"Learner's Self Assessment", u"Learner's Final Grade"],
self.staff_area_page.learner_report_sections
)
self.assertIn('A response was not found for this learner', self.staff_area_page.learner_report_text)
self.assertEqual([], self.staff_area_page.learner_report_sections)
# Verify that the Learner Response has been replaced with a message about the removal
self.staff_area_page.expand_learner_report_sections()
self.assertIn("Learner submission removed", self.staff_area_page.learner_response)
class FileUploadTest(OpenAssessmentTest):
......
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