Commit 98be9cea by Tim Krones

StepBuilder: Fix inconsistent feedback for MCQs.

parent 1c49b875
...@@ -195,7 +195,7 @@ function MRQBlock(runtime, element) { ...@@ -195,7 +195,7 @@ function MRQBlock(runtime, element) {
handleReview: function(result) { handleReview: function(result) {
$.each(result.submissions, function (index, value) { $.each(result.submissions, function (index, value) {
$('input[type="checkbox"][value="' + value + '"]').prop('checked', true) $('input[type="checkbox"][value="' + value + '"]').prop('checked', true);
}); });
$('input', element).prop('disabled', true); $('input', element).prop('disabled', true);
}, },
......
...@@ -89,8 +89,15 @@ function MentoringStepBlock(runtime, element) { ...@@ -89,8 +89,15 @@ function MentoringStepBlock(runtime, element) {
var child = children[i]; var child = children[i];
if (child && child.name !== undefined) { // Check if we are dealing with a question if (child && child.name !== undefined) { // Check if we are dealing with a question
var result = results[child.name]; var result = results[child.name];
callIfExists(child, 'handleSubmit', result, options); // Call handleReview first to ensure that choice-level feedback for MCQs is displayed:
// Before displaying feedback for a given choice, handleSubmit checks if it is selected.
// (If it isn't, we don't want to display feedback for it.)
// handleReview is responsible for setting the "checked" property to true
// for each choice that the student selected as part of their most recent submission.
// If it is called after handleSubmit, the check mentioned above will fail,
// and no feedback will be displayed.
callIfExists(child, 'handleReview', result); callIfExists(child, 'handleReview', result);
callIfExists(child, 'handleSubmit', result, options);
} }
} }
}, },
...@@ -100,7 +107,7 @@ function MentoringStepBlock(runtime, element) { ...@@ -100,7 +107,7 @@ function MentoringStepBlock(runtime, element) {
}, },
hasQuestion: function() { hasQuestion: function() {
return $('.sb-step', element).data('has-question') return $('.sb-step', element).data('has-question');
}, },
updateChildren: function() { updateChildren: function() {
......
from mock import patch from mock import patch
from ddt import ddt, data from ddt import ddt, data, unpack
from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
...@@ -497,6 +497,64 @@ class StepBuilderTest(MentoringAssessmentBaseTest, MultipleSliderBlocksTestMixin ...@@ -497,6 +497,64 @@ class StepBuilderTest(MentoringAssessmentBaseTest, MultipleSliderBlocksTestMixin
if extended_feedback: if extended_feedback:
self.extended_feedback_checks(step_builder, controls, expected_results) self.extended_feedback_checks(step_builder, controls, expected_results)
@data(
(0, "Yes", "Great!", True, CORRECT),
(1, "Maybe not", "Ah, damn.", False, INCORRECT),
(2, "I don't understand", "Really?", False, INCORRECT),
)
@unpack
def test_mcq_feedback(self, choice_index, choice_text, expected_feedback, correct, step_result):
params = {
"max_attempts": 1,
"extended_feedback": True,
}
step_builder, controls = self.load_assessment_scenario("step_builder_mcq_feedback.xml", params)
# Step 1
# Submit MCQ, go to review step
self.single_choice_question(None, step_builder, controls, choice_text, step_result, last=True)
# Check MCQ feedback
self.review_mcq(step_builder, choice_index, expected_feedback, correct)
# Reload page
self.browser.execute_script("$(document).html(' ');")
step_builder, controls = self.go_to_assessment()
# Check MCQ feedback
self.review_mcq(step_builder, choice_index, expected_feedback, correct)
# Go back to review step
controls.review_link.click()
# Check MCQ feedback
self.review_mcq(step_builder, choice_index, expected_feedback, correct)
def review_mcq(self, step_builder, choice_index, expected_feedback, correct):
correctness = 'correct' if correct else 'incorrect'
mcq_link = step_builder.find_elements_by_css_selector('.{}-list li a'.format(correctness))[0]
mcq_link.click()
mcq = step_builder.find_element_by_css_selector(".xblock-v1[data-name='mcq_1_1']")
self.assert_choice_feedback(mcq, choice_index, expected_feedback, correct)
def assert_choice_feedback(self, mcq, choice_index, expected_text, correct=True):
"""
Asserts that feedback for given element contains particular text
"""
choice = mcq.find_elements_by_css_selector(".choices-list .choice")[choice_index]
choice_result = choice.find_element_by_css_selector('.choice-result')
feedback_popup = choice.find_element_by_css_selector(".choice-tips")
checkmark_class = 'checkmark-correct' if correct else 'checkmark-incorrect'
self.wait_until_visible(feedback_popup)
self.assertEqual(feedback_popup.text, expected_text)
self.assert_choice_result(choice_result, checkmark_class=checkmark_class)
def assert_choice_result(self, choice_result, checkmark_class):
result_classes = choice_result.get_attribute('class').split()
self.wait_until_visible(choice_result)
self.assertIn(checkmark_class, result_classes)
def test_review_tips(self): def test_review_tips(self):
params = { params = {
"max_attempts": 3, "max_attempts": 3,
......
<step-builder url_name="step-builder" display_name="Step Builder"
max_attempts="{{max_attempts}}" extended_feedback="{{extended_feedback}}">
<sb-step display_name="First step">
<pb-mcq name="mcq_1_1" question="Do you like this MCQ?" correct_choices='["yes"]'>
<pb-choice value="yes">Yes</pb-choice>
<pb-choice value="maybenot">Maybe not</pb-choice>
<pb-choice value="understand">I don't understand</pb-choice>
<pb-tip values='["yes"]'>Great!</pb-tip>
<pb-tip values='["maybenot"]'>Ah, damn.</pb-tip>
<pb-tip values='["understand"]'><div id="test-custom-html">Really?</div></pb-tip>
</pb-mcq>
</sb-step>
<sb-review-step>
<sb-review-score/>
</sb-review-step>
</step-builder>
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