Commit 55712d11 by cahrens

Show checkmarks when "Show Answer" is clicked.

TNL-6357
parent d4df4268
...@@ -20,6 +20,7 @@ except ImportError: ...@@ -20,6 +20,7 @@ except ImportError:
from pytz import utc from pytz import utc
from capa.capa_problem import LoncapaProblem, LoncapaSystem from capa.capa_problem import LoncapaProblem, LoncapaSystem
from capa.inputtypes import Status
from capa.responsetypes import StudentInputError, ResponseError, LoncapaProblemError from capa.responsetypes import StudentInputError, ResponseError, LoncapaProblemError
from capa.util import convert_files_to_filenames, get_inner_html_from_xpath from capa.util import convert_files_to_filenames, get_inner_html_from_xpath
from xblock.fields import Boolean, Dict, Float, Integer, Scope, String, XMLString from xblock.fields import Boolean, Dict, Float, Integer, Scope, String, XMLString
...@@ -942,7 +943,12 @@ class CapaMixin(CapaFields): ...@@ -942,7 +943,12 @@ class CapaMixin(CapaFields):
""" """
For the "show answer" button. 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 = dict()
event_info['problem_id'] = self.location.to_deprecated_string() event_info['problem_id'] = self.location.to_deprecated_string()
...@@ -968,7 +974,13 @@ class CapaMixin(CapaFields): ...@@ -968,7 +974,13 @@ class CapaMixin(CapaFields):
new_answer = {answer_id: answers[answer_id]} new_answer = {answer_id: answers[answer_id]}
new_answers.update(new_answer) 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? # Figure out if we should move these to capa_problem?
def get_problem(self, _data): def get_problem(self, _data):
......
...@@ -457,24 +457,6 @@ describe 'Problem', -> ...@@ -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.' 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', -> describe 'radio text question', ->
radio_text_xml=''' radio_text_xml='''
<section class="problem"> <section class="problem">
......
...@@ -681,17 +681,8 @@ ...@@ -681,17 +681,8 @@
var answers; var answers;
answers = response.answers; answers = response.answers;
$.each(answers, function(key, value) { $.each(answers, function(key, value) {
var answer, choice, i, len, results; var answer;
if ($.isArray(value)) { 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 {
answer = that.$('#answer_' + key + ', #solution_' + key); answer = that.$('#answer_' + key + ', #solution_' + key);
edx.HtmlUtils.setHtml(answer, edx.HtmlUtils.HTML(value)); edx.HtmlUtils.setHtml(answer, edx.HtmlUtils.HTML(value));
Collapsible.setCollapsibles(answer); Collapsible.setCollapsibles(answer);
...@@ -722,7 +713,7 @@ ...@@ -722,7 +713,7 @@
display = that.inputtypeDisplays[$(inputtype).attr('id')]; display = that.inputtypeDisplays[$(inputtype).attr('id')];
showMethod = that.inputtypeShowAnswerMethods[cls]; showMethod = that.inputtypeShowAnswerMethods[cls];
if (showMethod != null) { if (showMethod != null) {
results.push(showMethod(inputtype, display, answers)); results.push(showMethod(inputtype, display, answers, response.correct_status_html));
} else { } else {
results.push(void 0); results.push(void 0);
} }
...@@ -947,10 +938,10 @@ ...@@ -947,10 +938,10 @@
var $status; var $status;
$status = $('#status_' + id); $status = $('#status_' + id);
if ($status[0]) { if ($status[0]) {
$status.removeAttr('class').addClass('unanswered'); $status.removeAttr('class').addClass('status unanswered');
} else { } else {
$('<span>', { $('<span>', {
class: 'unanswered', class: 'status unanswered',
style: 'display: inline-block;', style: 'display: inline-block;',
id: 'status_' + id id: 'status_' + id
}); });
...@@ -1030,16 +1021,30 @@ ...@@ -1030,16 +1021,30 @@
}; };
Problem.prototype.inputtypeShowAnswerMethods = { Problem.prototype.inputtypeShowAnswerMethods = {
choicegroup: function(element, display, answers) { choicegroup: function(element, display, answers, correctStatusHtml) {
var answer, choice, inputId, i, len, results, $element; var answer, choice, inputId, i, len, results, $element, $inputLabel, $inputStatus;
$element = $(element); $element = $(element);
inputId = $element.attr('id').replace(/inputtype_/, ''); inputId = $element.attr('id').replace(/inputtype_/, '');
answer = answers[inputId]; answer = answers[inputId];
results = []; results = [];
for (i = 0, len = answer.length; i < len; i++) { for (i = 0, len = answer.length; i < len; i++) {
choice = answer[i]; choice = answer[i];
results.push($element.find('#input_' + inputId + '_' + choice).parent('label'). $inputLabel = $element.find('#input_' + inputId + '_' + choice).parent('label');
addClass('choicegroup_correct')); $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; return results;
}, },
......
...@@ -413,10 +413,17 @@ class ProblemPage(PageObject): ...@@ -413,10 +413,17 @@ class ProblemPage(PageObject):
""" """
Check if correct answer/choice highlighted for choice group. 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: 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 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 return True
@property @property
......
...@@ -535,6 +535,35 @@ class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): ...@@ -535,6 +535,35 @@ class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin):
else: else:
self.problem_page.click_choice("choice_choice_2") 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): 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