Commit feb1c82d by Christina Roberts Committed by GitHub

Merge pull request #14415 from edx/christina/tnl-6357

Show checkmarks when "Show Answer" is clicked.
parents 327ffa92 55712d11
......@@ -20,6 +20,7 @@ except ImportError:
from pytz import utc
from capa.capa_problem import LoncapaProblem, LoncapaSystem
from capa.inputtypes import Status
from capa.responsetypes import StudentInputError, ResponseError, LoncapaProblemError
from capa.util import convert_files_to_filenames, get_inner_html_from_xpath
from xblock.fields import Boolean, Dict, Float, Integer, Scope, String, XMLString
......@@ -942,7 +943,12 @@ class CapaMixin(CapaFields):
"""
For the "show answer" button.
Returns the answers: {'answers' : answers}
Returns the answers and rendered "correct status span" HTML:
{'answers' : answers, 'correct_status_html': correct_status_span_html}.
The "correct status span" HTML is injected beside the correct answers
for radio button and checkmark problems, so that there is a visual
indication of the correct answers that is not solely based on color
(and also screen reader text).
"""
event_info = dict()
event_info['problem_id'] = self.location.to_deprecated_string()
......@@ -968,7 +974,13 @@ class CapaMixin(CapaFields):
new_answer = {answer_id: answers[answer_id]}
new_answers.update(new_answer)
return {'answers': new_answers}
return {
'answers': new_answers,
'correct_status_html': self.runtime.render_template(
'status_span.html',
{'status': Status('correct', self.runtime.service(self, "i18n").ugettext)}
)
}
# Figure out if we should move these to capa_problem?
def get_problem(self, _data):
......
......@@ -457,24 +457,6 @@ describe 'Problem', ->
expect(window.SR.readText).toHaveBeenCalledWith 'Answers to this problem are now shown. Navigate through the problem to review it with answers inline.'
describe 'multiple choice question', ->
beforeEach ->
@problem.el.prepend '''
<label for="input_1_1_1"><input type="checkbox" name="input_1_1" id="input_1_1_1" value="1"> One</label>
<label for="input_1_1_2"><input type="checkbox" name="input_1_1" id="input_1_1_2" value="2"> Two</label>
<label for="input_1_1_3"><input type="checkbox" name="input_1_1" id="input_1_1_3" value="3"> Three</label>
<label for="input_1_2_1"><input type="radio" name="input_1_2" id="input_1_2_1" value="1"> Other</label>
'''
it 'set the correct_answer attribute on the choice', ->
spyOn($, 'postWithPrefix').and.callFake (url, callback) ->
callback answers: '1_1': [2, 3]
@problem.show()
expect($('label[for="input_1_1_1"]')).not.toHaveAttr 'correct_answer', 'true'
expect($('label[for="input_1_1_2"]')).toHaveAttr 'correct_answer', 'true'
expect($('label[for="input_1_1_3"]')).toHaveAttr 'correct_answer', 'true'
expect($('label[for="input_1_2_1"]')).not.toHaveAttr 'correct_answer', 'true'
describe 'radio text question', ->
radio_text_xml='''
<section class="problem">
......
......@@ -681,17 +681,8 @@
var answers;
answers = response.answers;
$.each(answers, function(key, value) {
var answer, choice, i, len, results;
if ($.isArray(value)) {
results = [];
for (i = 0, len = value.length; i < len; i++) {
choice = value[i];
results.push(that.$('label[for="input_' + key + '_' + choice + '"]').attr({
correct_answer: 'true'
}));
}
return results;
} else {
var answer;
if (!$.isArray(value)) {
answer = that.$('#answer_' + key + ', #solution_' + key);
edx.HtmlUtils.setHtml(answer, edx.HtmlUtils.HTML(value));
Collapsible.setCollapsibles(answer);
......@@ -722,7 +713,7 @@
display = that.inputtypeDisplays[$(inputtype).attr('id')];
showMethod = that.inputtypeShowAnswerMethods[cls];
if (showMethod != null) {
results.push(showMethod(inputtype, display, answers));
results.push(showMethod(inputtype, display, answers, response.correct_status_html));
} else {
results.push(void 0);
}
......@@ -947,10 +938,10 @@
var $status;
$status = $('#status_' + id);
if ($status[0]) {
$status.removeAttr('class').addClass('unanswered');
$status.removeAttr('class').addClass('status unanswered');
} else {
$('<span>', {
class: 'unanswered',
class: 'status unanswered',
style: 'display: inline-block;',
id: 'status_' + id
});
......@@ -1030,16 +1021,30 @@
};
Problem.prototype.inputtypeShowAnswerMethods = {
choicegroup: function(element, display, answers) {
var answer, choice, inputId, i, len, results, $element;
choicegroup: function(element, display, answers, correctStatusHtml) {
var answer, choice, inputId, i, len, results, $element, $inputLabel, $inputStatus;
$element = $(element);
inputId = $element.attr('id').replace(/inputtype_/, '');
answer = answers[inputId];
results = [];
for (i = 0, len = answer.length; i < len; i++) {
choice = answer[i];
results.push($element.find('#input_' + inputId + '_' + choice).parent('label').
addClass('choicegroup_correct'));
$inputLabel = $element.find('#input_' + inputId + '_' + choice).parent('label');
$inputStatus = $inputLabel.find('#status_' + inputId);
// If the correct answer was already Submitted before "Show Answer" was selected,
// the status HTML will already be present. Otherwise, inject the status HTML.
// If the learner clicked a different answer after Submit, their submitted answers
// will be marked as "unanswered". In that case, for correct answers update the
// classes accordingly.
if ($inputStatus.hasClass('unanswered')) {
$inputStatus.removeAttr('class').addClass('status correct');
$inputLabel.addClass('choicegroup_correct');
} else if (!$inputLabel.hasClass('choicegroup_correct')) {
// If the status HTML is not already present (due to clicking Submit), append
// the status HTML for correct answers.
results.push($inputLabel.addClass('choicegroup_correct').append(correctStatusHtml));
}
}
return results;
},
......
......@@ -413,10 +413,17 @@ class ProblemPage(PageObject):
"""
Check if correct answer/choice highlighted for choice group.
"""
xpath = '//fieldset/div[contains(@class, "field")][{0}]/label[contains(@class, "choicegroup_correct")]'
correct_status_xpath = '//fieldset/div[contains(@class, "field")][{0}]/label[contains(@class, "choicegroup_correct")]/span[contains(@class, "status correct")]' # pylint: disable=line-too-long
any_status_xpath = '//fieldset/div[contains(@class, "field")][{0}]/label/span'
for choice in correct_choices:
if not self.q(xpath=xpath.format(choice)).is_present():
if not self.q(xpath=correct_status_xpath.format(choice)).is_present():
return False
# Check that there is only a single status span, as there were some bugs with multiple
# spans (with various classes) being appended.
if not len(self.q(xpath=any_status_xpath.format(choice)).results) == 1:
return False
return True
@property
......
......@@ -535,6 +535,35 @@ class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin):
else:
self.problem_page.click_choice("choice_choice_2")
@attr(shard=7)
def test_can_show_answer(self):
"""
Scenario: Verifies that show answer button is working as expected.
Given that I am on courseware page
And I can see a CAPA problem with show answer button
When I click "Show Answer" button
The correct answer is displayed with a single correctness indicator.
"""
# Click the correct answer, but don't submit yet. No correctness shows.
self.answer_problem('correct')
self.assertFalse(self.problem_page.is_correct_choice_highlighted(correct_choices=[3]))
# After submit, the answer should be marked as correct.
self.problem_page.click_submit()
self.assertTrue(self.problem_page.is_correct_choice_highlighted(correct_choices=[3]))
# Switch to an incorrect answer. This will hide the correctness indicator.
self.answer_problem('incorrect')
self.assertFalse(self.problem_page.is_correct_choice_highlighted(correct_choices=[3]))
# Now click Show Answer. A single correctness indicator should be shown.
self.problem_page.click_show()
self.assertTrue(self.problem_page.is_correct_choice_highlighted(correct_choices=[3]))
# Finally, make sure that clicking Show Answer moved focus to the correct place.
self.problem_page.wait_for_focus_on_problem_meta()
class RadioProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin):
"""
......
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