Commit 8ac56fc2 by Jillian Vogel

Improves the accessibility of the Problem Builder, Step Builder, and their related XBlocks.

* Moves the choice-label <input> elements inside of their <label> tags.
* Wraps long-answer and slider question text in a <label> tag.
* Uses <th> instead of <td> elements inside <thead>, for the instructor tool and plot preview tables.
* Links the feedback, and choice-tip text with the choice labels via aria-describedby.
* Wraps the choice-result feedback icons inside the label elements, to match CAPA a11y design.
* Adds translated, aria-visible labels for the "correct answer/choice" checkmark and "incorrect answer/choice" X.
* Adds the 'aria-live="polite"' attribute to the divs whose content changes dynamically.
* Removes block-level children from <legend>, placing the h3.question-title outside the <fieldset>.
* Fixes tests broken by above commits
* Adds tests for new aria-label attributes..
parent efe6f231
......@@ -52,7 +52,9 @@
}
.data-export-results thead {
border-bottom: 2px solid #999;
white-space: nowrap;
}
.data-export-results th,
.data-export-results td {
border-left: 1px solid #999;
padding: 5px;
......
......@@ -9,12 +9,14 @@
border-bottom: 2px solid #999;
background-color: #ddd;
font-weight: bold;
white-space: nowrap;
}
.sb-plot tr:nth-child(even) {
background-color: #eee;
}
.sb-plot th,
.sb-plot td {
border-left: 1px solid #999;
padding: 5px;
......
......@@ -41,7 +41,7 @@
margin-top: 10px;
}
.mentoring h3 {
.xblock .mentoring h3 {
margin-top: 0px;
margin-bottom: 7px;
}
......
......@@ -8,8 +8,8 @@
}
.mentoring .questionnaire .choice-result {
display: table-cell;
width: 40px;
display: inline-block;
width: 34px;
vertical-align: top;
cursor: pointer;
float: none;
......@@ -78,16 +78,12 @@
}
.mentoring .choices-list .choice-selector {
display: table-cell;
vertical-align: top;
width: 28px;
padding-top: 3px;
padding-right: 5px;
display: inline-block;
}
.mentoring .choice-tips-container,
.mentoring .choice-label {
display: table-cell;
vertical-align: top;
line-height: 1.3;
padding-top: 4px;
width: 50%;
}
......@@ -35,9 +35,11 @@ function AnswerBlock(runtime, element) {
if (result.status) {
if (result.status === "correct") {
checkmark.addClass('checkmark-correct icon-ok fa-check');
checkmark.attr('aria-label', checkmark.data('label_correct'));
}
else {
checkmark.addClass('checkmark-incorrect icon-exclamation fa-exclamation');
checkmark.attr('aria-label', checkmark.data('label_incorrect'));
}
}
},
......
......@@ -15,6 +15,7 @@ function MentoringAssessmentView(runtime, element, mentoring) {
checkmark.removeClass('checkmark-partially-correct icon-ok fa-check');
checkmark.removeClass('checkmark-incorrect icon-exclamation fa-exclamation');
checkmark.removeClass('checkmark-clickable');
checkmark.attr('aria-label', '');
checkmark.off('click');
// Clear all selections
......@@ -266,10 +267,13 @@ function MentoringAssessmentView(runtime, element, mentoring) {
if (response.completed === 'partial') {
checkmark.addClass('checkmark-partially-correct icon-ok fa-check');
checkmark.attr('aria-label', checkmark.data('label_partial'));
} else if (response.completed === 'correct') {
checkmark.addClass('checkmark-correct icon-ok fa-check');
checkmark.attr('aria-label', checkmark.data('label_correct'));
} else {
checkmark.addClass('checkmark-incorrect icon-exclamation fa-exclamation');
checkmark.attr('aria-label', checkmark.data('label_incorrect'));
}
submitDOM.attr('disabled', 'disabled');
......
......@@ -82,10 +82,13 @@ function MentoringWithStepsBlock(runtime, element) {
function showFeedback(response) {
if (response.step_status === 'correct') {
checkmark.addClass('checkmark-correct icon-ok fa-check');
checkmark.attr('aria-label', checkmark.data('label_correct'));
} else if (response.step_status === 'partial') {
checkmark.addClass('checkmark-partially-correct icon-ok fa-check');
checkmark.attr('aria-label', checkmark.data('label_partial'));
} else {
checkmark.addClass('checkmark-incorrect icon-exclamation fa-exclamation');
checkmark.attr('aria-label', checkmark.data('label_incorrect'));
}
var step = getActiveStep();
if (typeof step.showFeedback == 'function') {
......@@ -166,6 +169,7 @@ function MentoringWithStepsBlock(runtime, element) {
checkmark.removeClass('checkmark-correct icon-ok fa-check');
checkmark.removeClass('checkmark-partially-correct icon-ok fa-check');
checkmark.removeClass('checkmark-incorrect icon-exclamation fa-exclamation');
checkmark.attr('aria-label', '');
hideAllSteps();
hideReviewStep();
attemptsDOM.html('');
......
......@@ -88,6 +88,7 @@ function MessageView(element, mentoring) {
this.allResultsDOM.removeClass(
'checkmark-incorrect icon-exclamation fa-exclamation checkmark-correct icon-ok fa-check'
);
this.allResultsDOM.attr('aria-label', '');
}
};
}
......@@ -136,9 +137,11 @@ function MCQBlock(runtime, element) {
if (result.status === "correct") {
choiceInputDOM.addClass('correct');
choiceResultDOM.addClass('checkmark-correct icon-ok fa-check');
choiceResultDOM.attr('aria-label', choiceResultDOM.data('label_correct'));
} else {
choiceDOM.addClass('incorrect');
choiceResultDOM.addClass('checkmark-incorrect icon-exclamation fa-exclamation');
choiceResultDOM.attr('aria-label', choiceResultDOM.data('label_incorrect'));
}
choiceResultDOM.off('click').on('click', function() {
if (choiceTipsDOM.html() !== '') {
......@@ -230,9 +233,11 @@ function MRQBlock(runtime, element) {
if (choice.completed) {
choiceDOM.addClass('correct');
choiceResultDOM.addClass('checkmark-correct icon-ok fa-check');
choiceResultDOM.attr('aria-label', choiceResultDOM.data('label_correct'));
} else if (!choice.completed) {
choiceDOM.addClass('incorrect');
choiceResultDOM.addClass('checkmark-incorrect icon-exclamation fa-exclamation');
choiceResultDOM.attr('aria-label', choiceResultDOM.data('label_incorrect'));
}
mentoring.setContent(choiceTipsDOM, choice.tips);
......
.themed-xblock.mentoring .questionnaire .choice-result {
display: table-cell;
}
.themed-xblock.mentoring .choice-result::before {
content: "";
display: block;
......@@ -40,8 +36,6 @@ div.course-wrapper section.course-content .themed-xblock.mentoring p:empty {
.themed-xblock.mentoring .choice-label {
display: table-cell;
vertical-align: middle;
width: 100%;
padding-bottom: 10px;
}
.themed-xblock.mentoring .choice-label span.low {
......
{% load i18n %}
<div class="xblock-answer" data-completed="{{ self.completed }}">
{% if not hide_header %}<h3 class="question-title">{{ self.display_name_with_default }}</h3>{% endif %}
<p>{{ self.question|safe }}</p>
<label><p>{{ self.question|safe }}</p>
<textarea
class="answer editable" cols="50" rows="10" name="input"
data-min_characters="{{ self.min_characters }}"
>{{ self.student_input }}</textarea>
</label>
<div style="display: none;" class="orig-student-answer">{{ self.student_input }}</div> <!-- To detect edits -->
<span class="answer-checkmark fa icon-2x"></span>
<span class="answer-checkmark fa icon-2x" aria-label=""
data-label_correct="{% trans "Correct" %}" data-label_incorrect="{% trans "Incorrect" %}"></span>
</div>
......@@ -59,17 +59,18 @@
</div>
</div>
<div id="results" class="data-export-results">
<div id="results-wrapper" aria-live="polite">
<div id="results" class="data-export-results">
<table>
<thead>
<tr>
<td>{% trans "Section" %}</td>
<td>{% trans "Subsection" %}</td>
<td>{% trans "Unit" %}</td>
<td>{% trans "Type" %}</td>
<td>{% trans "Question" %}</td>
<td>{% trans "Answer" %}</td>
<td>{% trans "Username" %}</td>
<th>{% trans "Section" %}</th>
<th>{% trans "Subsection" %}</th>
<th>{% trans "Unit" %}</th>
<th>{% trans "Type" %}</th>
<th>{% trans "Question" %}</th>
<th>{% trans "Answer" %}</th>
<th>{% trans "Username" %}</th>
</tr>
</thead>
<tbody></tbody>
......@@ -82,12 +83,13 @@
<button id="next-page">Next</button>
<button id="last-page">Last</button>
</div>
</div>
</div>
<div class="data-export-status"></div>
<div class="data-export-status"></div>
<div class="data-export-actions">
<div class="data-export-actions">
<button class="data-export-download">{% trans "Download as CSV" %}</button>
<button class="data-export-cancel">{% trans "Cancel search" %}</button>
<button class="data-export-delete">{% trans "Delete results" %}</button>
</div>
</div>
<fieldset class="choices questionnaire">
<legend class="question">
{% if not hide_header %}<h3 class="question-title">{{ self.display_name_with_default }}</h3>{% endif %}
<p>{{ self.question|safe }}</p>
</legend>
{% load i18n %}
{% if not hide_header %}
<h3 class="question-title" id="heading_{{ self.html_id }}">{{ self.display_name_with_default }}</h3>
{% endif %}
<fieldset class="choices questionnaire" id="{{ self.html_id }}">
<legend class="question field-group-hd">{{ self.question|safe }}</legend>
<div class="choices-list">
{% for choice in custom_choices %}
<div class="choice">
<div class="choice-result fa icon-2x"></div>
<div class="choice" aria-live="polite" aria-atomic="true">
<label class="choice-label"
aria-describedby="feedback_{{ self.html_id }} choice_tips_{{ self.html_id }}-{{ forloop.counter }}">
<div class="choice-result fa icon-2x" aria-label=""
data-label_correct="{% trans "Correct" %}" data-label_incorrect="{% trans "Incorrect" %}"></div>
<div class="choice-selector">
<input id="choice-{{ self.html_id }}-{{ forloop.counter }}" type="radio"
name="{{ self.name }}" value="{{ choice.value }}"
<input type="radio" name="{{ self.name }}" value="{{ choice.value }}"
{% if self.student_choice == choice.value and not hide_prev_answer %} checked{% endif %}
/>
</div>
<label class="choice-label" for="choice-{{ self.html_id }}-{{ forloop.counter }}">
{{ choice.content|safe }}
</label>
<div class="choice-tips-container">
<div class="choice-tips"></div>
<div class="choice-tips" id="choice_tips_{{ self.html_id }}-{{ forloop.counter }}"></div>
</div>
</div>
{% endfor %}
<div class="feedback"></div>
<div class="feedback" id="feedback_{{ self.html_id }}"></div>
</div>
</fieldset>
......@@ -14,7 +14,9 @@
{% endfor %}
<div class="submit">
<span class="step-overall-checkmark fa icon-2x fa-fw"></span>
<span class="step-overall-checkmark fa icon-2x fa-fw" aria-label=""
data-label_correct="{% trans "Correct" %}" data-label_incorrect="{% trans "Incorrect" %}"
data-label_partial="{% trans "Partially correct" %}"></span>
<input type="button" class="input-main" value="Submit" disabled="disabled" />
<input type="button" class="input-next" value="Next Step" disabled="disabled" />
<input type="button" class="input-review" value="Review grade" disabled="disabled" />
......
<fieldset class="choices questionnaire" data-hide_results="{{self.hide_results}}" data-hide_prev_answer="{{hide_prev_answer}}">
<legend class="question">
{% if not hide_header %}<h3 class="question-title">{{ self.display_name_with_default }}</h3>{% endif %}
<p>{{ self.question|safe }}</p>
</legend>
{% load i18n %}
{% if not hide_header %}
<h3 class="question-title" id="heading_{{ self.html_id }}">{{ self.display_name_with_default }}</h3>
{% endif %}
<fieldset class="choices questionnaire" id="{{ self.html_id }}"
data-hide_results="{{ self.hide_results }}" data-hide_prev_answer="{{ hide_prev_answer }}">
<legend class="question field-group-hd">{{ self.question|safe }}</legend>
<div class="choices-list">
{% for choice in custom_choices %}
<div class="choice">
<div class="choice-result fa icon-2x"></div>
<div class="choice" aria-live="polite" aria-atomic="true">
<div class="choice-result fa icon-2x" id="result_{{ self.html_id }}-{{ forloop.counter }}" aria-label=""
data-label_correct="{% trans "Correct" %}" data-label_incorrect="{% trans "Incorrect" %}"></div>
<label class="choice-label" aria-describedby="feedback_{{ self.html_id }}
result_{{ self.html_id }}-{{ forloop.counter }}
choice_tips_{{ self.html_id }}-{{ forloop.counter }}">
<div class="choice-selector">
<input id="choice-{{ self.html_id }}-{{ forloop.counter }}" type="checkbox"
name="{{ self.name }}" value="{{ choice.value }}"
<input type="checkbox" name="{{ self.name }}" value="{{ choice.value }}"
{% if choice.value in self.student_choices and not hide_prev_answer %} checked{% endif %}
/>
</div>
<label class="choice-label" for="choice-{{ self.html_id }}-{{ forloop.counter }}">
{{ choice.content|safe }}
</label>
<div class="choice-tips-container">
<div class="choice-tips"></div>
<div class="choice-tips" id="choice_tips_{{ self.html_id }}-{{ forloop.counter }}"></div>
</div>
</div>
{% endfor %}
<div class="feedback"></div>
<div class="feedback" id="feedback_{{ self.html_id }}"></div>
</div>
</fieldset>
......@@ -6,9 +6,9 @@
<table>
<thead>
<tr>
<td>{% trans "Claim" %}</td>
<td>{% trans "Question 1" %}</td>
<td>{% trans "Question 2" %}</td>
<th>{% trans "Claim" %}</th>
<th>{% trans "Question 1" %}</th>
<th>{% trans "Question 2" %}</th>
</tr>
</thead>
<tbody>
......
<fieldset class="rating questionnaire">
<legend class="question">
{% if not hide_header %}<h3 class="question-title">{{ self.display_name_with_default }}</h3>{% endif %}
<p>{{ self.question|safe }}</p>
</legend>
{% load i18n %}
{% if not hide_header %}
<h3 class="question-title" id="heading_{{ self.html_id }}">{{ self.display_name_with_default }}</h3>
{% endif %}
<fieldset class="rating questionnaire" id="{{ self.html_id }}">
<legend class="question field-group-hd">{{ self.question|safe }}</legend>
<div class="choices-list">
{% for i in '12345' %}
<div class="choice">
<div class="choice-result fa icon-2x"></div>
<div class="choice" aria-live="polite" aria-atomic="true">
<label class="choice-label"
aria-describedby="feedback_{{ self.html_id }} choice_tips_{{ self.html_id }}-{{ i }}">
<div class="choice-result fa icon-2x" aria-label=""
data-label_correct="{% trans "Correct" %}" data-label_incorrect="{% trans "Incorrect" %}"></div>
<div class="choice-selector">
<input id="choice-{{ self.html_id }}-{{i}}" type="radio"
name="{{ self.name }}" value="{{i}}"
<input type="radio" name="{{ self.name }}" value="{{i}}"
{% if self.student_choice == i and not hide_prev_answer %} checked{%else%} data-student-choice='{{self.student_choice}}'{% endif %}
/>
</div>
<label class="choice-label" for="choice-{{ self.html_id }}-{{i}}">
{{i}}
{% if i == '1' %} - {{ self.low|safe }}{% endif %}
{% if i == '5' %} - {{ self.high|safe }}{% endif %}
</div>
</label>
<div class="choice-tips-container">
<div class="choice-tips"></div>
<div class="choice-tips" id="choice_tips_{{ self.html_id }}-{{ i }}"></div>
</div>
</div>
{% endfor %}
{% for choice in custom_choices %}
<div class="choice">
<div class="choice-result fa icon-2x"></div>
<div class="choice" aria-live="polite" aria-atomic="true">
<label class="choice-label"
aria-describedby="feedback_{{ self.html_id }} choice_tips_{{ self.html_id }}-{{ forloop.counter }}">
<div class="choice-result fa icon-2x" aria-label=""
data-label_correct="{% trans "Correct" %}" data-label_incorrect="{% trans "Incorrect" %}"></div>
<div class="choice-selector">
<input id="choice-{{ self.html_id }}-custom{{ forloop.counter }}" type="radio"
name="{{ self.name }}" value="{{ choice.value }}"
<input type="radio" name="{{ self.name }}" value="{{ choice.value }}"
{% if self.student_choice == choice.value and not hide_prev_answer %} checked{%else%} data-student-choice='{{self.student_choice}}'{% endif %}
/>
</div>
<label class="choice-label" for="choice-{{ self.html_id }}-custom{{ forloop.counter }}">
{{ choice.content|safe }}
</label>
<div class="choice-tips-container">
<div class="choice-tips"></div>
<div class="choice-tips" id="choice_tips_{{ self.html_id }}-{{ forloop.counter }}"></div>
</div>
</div>
{% endfor %}
<div class="feedback"></div>
<div class="feedback" id="feedback_{{ self.html_id }}"></div>
</div>
</fieldset>
{% load i18n %}
<div class="xblock-pb-slider">
{% if not hide_header %}<h3 class="question-title">{{ title }}</h3>{% endif %}
{% if question %}
<p><label for="{{slider_id}}">{{ question|safe }} <span class="sr">({{instructions_string}})</span></label></p>
{% endif %}
<div class="pb-slider-box clearfix">
<input type="range"
id="{{slider_id}}" class="pb-slider-range" min="0" max="100" step="1" value="{{initial_value}}"
{% if not question %}aria-label="{{instructions_string}}"{% endif %}
>
<p><label>{{ question|safe }} <span class="sr">({{instructions_string}})</span>
<input type="range" id="{{ slider_id }}" class="pb-slider-range"
min="0" max="100" step="1" value="{{initial_value}}"
/>
</label></p>
<div class="pb-slider-min-label" aria-hidden="true">{{ min_label }}</div>
<div class="pb-slider-max-label" aria-hidden="true">{{ max_label }}</div>
</div>
<div class="clearfix">
<span class="submit-result fa icon-2x checkmark-correct icon-ok fa-check" style="visibility: hidden;"></span>
<span class="submit-result fa icon-2x checkmark-correct icon-ok fa-check"
style="visibility: hidden;" aria-label="{% trans "Complete" %}"></span>
</div>
</div>
<div class="sb-step" data-next-button-label="{{ self.next_button_label }}" {% if self.has_question %} data-has-question="true" {% endif %}>
<div class="sb-step" aria-live="polite"
data-next-button-label="{{ self.next_button_label }}" {% if self.has_question %} data-has-question="true" {% endif %}>
{% if show_title %}
<div class="title">
<h3>
......
......@@ -84,7 +84,7 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
return questionnaire.find_elements_by_css_selector(".choices-list .choice")[choice_index]
def _get_answer_checkmark(self, answer):
return answer.find_element_by_xpath("parent::*").find_element_by_css_selector(".answer-checkmark")
return answer.find_element_by_xpath("ancestor::node()[3]").find_element_by_css_selector(".answer-checkmark")
def _get_messages_element(self, mentoring):
return mentoring.find_element_by_css_selector('.messages')
......@@ -103,15 +103,25 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
def _assert_answer(self, answer, results_shown=True):
self.assertEqual(answer.get_attribute('value'), 'This is the answer')
answer_checkmark = self._get_answer_checkmark(answer)
self._assert_checkmark(answer_checkmark, shown=results_shown, checkmark_class='checkmark-correct')
self._assert_checkmark(answer_checkmark, shown=results_shown)
def _assert_checkmark(self, checkmark, shown=True, checkmark_class=None):
def _assert_checkmark(self, checkmark, correct=True, shown=True):
result_classes = checkmark.get_attribute('class').split()
result_label = checkmark.get_attribute('aria-label').strip()
if shown:
if correct:
checkmark_class = 'checkmark-correct'
checkmark_label = 'Correct'
else:
checkmark_class = 'checkmark-incorrect'
checkmark_label = 'Incorrect'
self.assertTrue(checkmark.is_displayed())
self.assertIn(checkmark_class, result_classes)
self.assertEquals(checkmark_label, result_label)
else:
self.assertFalse(checkmark.is_displayed())
self.assertEquals('', result_label)
def _assert_mcq(self, mcq, previous_answer_shown=True):
if previous_answer_shown:
......@@ -143,8 +153,7 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
choice_result.click()
feedback_popup = choice.find_element_by_css_selector(".choice-tips")
checkmark_class = 'checkmark-correct' if success else 'checkmark-incorrect'
self._assert_checkmark(choice_result, checkmark_class=checkmark_class)
self._assert_checkmark(choice_result, correct=success)
self.assertTrue(feedback_popup.is_displayed())
self.assertEqual(feedback_popup.text, expected_text)
......
......@@ -52,15 +52,19 @@ class QuestionnaireBlockTest(MentoringBaseTest):
# Initial MCQ status
mentoring = self.go_to_page('Mcq 1')
mcq1 = mentoring.find_element_by_css_selector('fieldset.choices')
mcq1_heading = mentoring.find_element_by_id('heading_' + mcq1.get_attribute('id'))
mcq2 = mentoring.find_element_by_css_selector('fieldset.rating')
mcq2_heading = mentoring.find_element_by_id('heading_' + mcq2.get_attribute('id'))
messages = mentoring.find_element_by_css_selector('.messages')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assert_messages_empty(messages)
self.assertFalse(submit.is_enabled())
self.assertEqual(mcq1.find_element_by_css_selector('legend').text, 'Question 1\nDo you like this MCQ?')
self.assertEqual(mcq2.find_element_by_css_selector('legend').text, 'Question 2\nHow do you rate this MCQ?')
self.assertEqual(mcq1_heading.text, 'Question 1')
self.assertEqual(mcq1.find_element_by_css_selector('legend').text, 'Do you like this MCQ?')
self.assertEqual(mcq2_heading.text, 'Question 2')
self.assertEqual(mcq2.find_element_by_css_selector('legend').text, 'How do you rate this MCQ?')
mcq1_choices = mcq1.find_elements_by_css_selector('.choices .choice')
mcq2_choices = mcq2.find_elements_by_css_selector('.rating .choice')
......@@ -141,8 +145,8 @@ class QuestionnaireBlockTest(MentoringBaseTest):
# Clicking outside the tips should hide the tips and clear the with-tips class.
mcq1_tips = mcq1.find_element_by_css_selector(".choice-tips .tip p")
mcq2_tips = mcq2.find_element_by_css_selector(".choice-tips .tip p")
mcq1.find_element_by_css_selector('.mentoring .question-title').click()
mcq2.find_element_by_css_selector('.mentoring .question-title').click()
mcq1_heading.click()
mcq2_heading.click()
mcq1_tip_containers = mcq1.find_elements_by_css_selector('.choice-tips-container.with-tips')
mcq2_tip_containers = mcq2.find_elements_by_css_selector('.choice-tips-container.with-tips')
self.assertEqual(len(mcq1_tip_containers), 0)
......@@ -161,7 +165,10 @@ class QuestionnaireBlockTest(MentoringBaseTest):
self.assertFalse(submit.is_enabled())
mcq_legend = mcq.find_element_by_css_selector('legend')
self.assertEqual(mcq_legend.text, 'Question\nWhat do you like in this MRQ?')
self.assertEqual(mcq_legend.text, 'What do you like in this MRQ?')
mcq_heading = mentoring.find_element_by_id('heading_' + mcq.get_attribute('id'))
self.assertEqual(mcq_heading.text, 'Question')
mcq_choices = mcq.find_elements_by_css_selector('.choices .choice')
......@@ -193,8 +200,7 @@ class QuestionnaireBlockTest(MentoringBaseTest):
# this could be a list comprehension, but a bit complicated one - hence explicit loop
for choice_wrapper in questionnaire.find_elements_by_css_selector(".choice"):
choice_label = choice_wrapper.find_element_by_css_selector("label")
result.append(choice_label.get_attribute('innerHTML').strip())
result.append(choice_label)
return result
@ddt.data(
......@@ -202,9 +208,10 @@ class QuestionnaireBlockTest(MentoringBaseTest):
'Mcq With Html Choices'
)
def test_questionnaire_html_choices(self, page):
mentoring = self.go_to_page(page)
question = mentoring.find_element_by_css_selector('legend p')
question = mentoring.find_element_by_css_selector('fieldset legend')
self.assertIn(
'What do <strong>you</strong> like in this ',
question.get_attribute('innerHTML').strip()
......@@ -220,8 +227,12 @@ class QuestionnaireBlockTest(MentoringBaseTest):
'<span style="font-color:red">Its bugs</span>'
]
options = self._get_questionnaire_options(choices_list)
self.assertEqual(expected_options, options)
# Ensure each questionnaire label contains the input item, and the expected option.
labels = self._get_questionnaire_options(choices_list)
self.assertEquals(len(labels), len(expected_options))
for idx, label in enumerate(labels):
self.assertEquals(len(label.find_elements_by_tag_name('input')), 1)
self.assertIn(expected_options[idx], label.get_attribute('innerHTML').strip())
self.assert_messages_empty(messages)
......
......@@ -544,16 +544,24 @@ class StepBuilderTest(MentoringAssessmentBaseTest, MultipleSliderBlocksTestMixin
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)
self.assert_choice_result(choice_result, correct)
def assert_choice_result(self, choice_result, correct):
if correct:
checkmark_class = 'checkmark-correct'
checkmark_label = 'Correct'
else:
checkmark_class = 'checkmark-incorrect'
checkmark_label = 'Incorrect'
def assert_choice_result(self, choice_result, checkmark_class):
result_classes = choice_result.get_attribute('class').split()
result_label = choice_result.get_attribute('aria-label').strip()
self.wait_until_visible(choice_result)
self.assertIn(checkmark_class, result_classes)
self.assertEquals(checkmark_label, result_label)
def test_review_tips(self):
params = {
......
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