From 1122c40f072dcda9744bdad7e90f249e16c2a641 Mon Sep 17 00:00:00 2001 From: cahrens Date: Fri, 9 Sep 2016 16:46:25 -0400 Subject: [PATCH] Moving ignore rules to relevant classes instead general rule. Also replaces section with div, updates short_id, and makes textbox accessible. TNL-5576, TNL-5575, TNL-5574, TNL-5671, TNL-5376 --- common/lib/capa/capa/capa_problem.py | 1 + common/lib/capa/capa/inputtypes.py | 13 +++++- common/lib/capa/capa/responsetypes.py | 11 +++-- common/lib/capa/capa/templates/codeinput.html | 21 ++++++---- common/lib/capa/capa/tests/helpers.py | 4 +- .../lib/capa/capa/tests/test_capa_problem.py | 2 +- .../lib/capa/capa/tests/test_html_render.py | 30 +++++++++----- .../capa/capa/tests/test_input_templates.py | 40 +++++++++++++++++++ common/lib/capa/capa/tests/test_inputtypes.py | 2 + .../lib/xmodule/xmodule/css/capa/display.scss | 6 +++ .../js/fixtures/codeinput_problem.html | 21 ++++++++++ .../xmodule/js/spec/capa/display_spec.coffee | 22 ++++++++++ .../xmodule/js/src/capa/display.coffee | 11 +++-- .../test/acceptance/pages/lms/staff_view.py | 2 +- .../acceptance/tests/lms/test_lms_problems.py | 2 +- .../tests/lms/test_problem_types.py | 31 +++++++++----- .../sass/course/courseware/_courseware.scss | 2 +- lms/templates/problem_ajax.html | 2 +- lms/templates/problem_notifications.html | 2 +- lms/templates/staff_problem_info.html | 12 +++--- 20 files changed, 187 insertions(+), 50 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/fixtures/codeinput_problem.html diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index be6c8549ec..c200cf4fd6 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -46,6 +46,7 @@ ACCESSIBLE_CAPA_INPUT_TYPES = [ 'optioninput', 'textline', 'formulaequationinput', + 'textbox', ] # these get captured as student responses diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 1365fde94a..25b5fe30b2 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -818,8 +818,17 @@ class CodeInput(InputTypeBase): self.setup_code_response_rendering() def _extra_context(self): - """Defined queue_len, add it """ - return {'queue_len': self.queue_len, } + """ + Define queue_len, arial_label and code mirror exit message context variables + """ + _ = self.capa_system.i18n.ugettext + return { + 'queue_len': self.queue_len, + 'aria_label': _('{programming_language} editor').format( + programming_language=self.loaded_attributes.get('mode') + ), + 'code_mirror_exit_message': _('Press ESC then TAB or click outside of the code editor to exit') + } #----------------------------------------------------------------------------- diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 7482ca72a2..447a34e7c6 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -253,23 +253,26 @@ class LoncapaResponse(object): """ _ = self.capa_system.i18n.ugettext - # get responsetype index to make responsetype label - response_index = self.xml.attrib['id'].split('_')[-1] + # response_id = problem_id + response index + response_id = self.xml.attrib['id'] + + response_index = response_id.split('_')[-1] # Translators: index here could be 1,2,3 and so on response_label = _(u'Question {index}').format(index=response_index) # wrap the content inside a section - tree = etree.Element('section') + tree = etree.Element('div') tree.set('class', 'wrapper-problem-response') tree.set('tabindex', '-1') tree.set('aria-label', response_label) + tree.set('role', 'group') if self.xml.get('multiple_inputtypes'): # add
to wrap all inputtypes content = etree.SubElement(tree, 'div') content.set('class', 'multi-inputs-group') content.set('role', 'group') - content.set('aria-labelledby', self.xml.get('id')) + content.set('aria-labelledby', response_id) else: content = tree diff --git a/common/lib/capa/capa/templates/codeinput.html b/common/lib/capa/capa/templates/codeinput.html index f2bffdbf57..57d4d82807 100644 --- a/common/lib/capa/capa/templates/codeinput.html +++ b/common/lib/capa/capa/templates/codeinput.html @@ -1,12 +1,16 @@ +<%page expression_filter="h"/> <%! from django.utils.translation import ugettext as _ from openedx.core.djangolib.markup import HTML %> -
- + >${value} + + ${code_mirror_exit_message} +
${HTML(msg)}
-
+
diff --git a/common/lib/capa/capa/tests/helpers.py b/common/lib/capa/capa/tests/helpers.py index 7ae7a3020d..8947a93552 100644 --- a/common/lib/capa/capa/tests/helpers.py +++ b/common/lib/capa/capa/tests/helpers.py @@ -90,10 +90,10 @@ def mock_capa_module(): return capa_module -def new_loncapa_problem(xml, capa_system=None, seed=723, use_capa_render_template=False): +def new_loncapa_problem(xml, problem_id='1', capa_system=None, seed=723, use_capa_render_template=False): """Construct a `LoncapaProblem` suitable for unit tests.""" render_template = capa_render_template if use_capa_render_template else None - return LoncapaProblem(xml, id='1', seed=seed, capa_system=capa_system or test_capa_system(render_template), + return LoncapaProblem(xml, id=problem_id, seed=seed, capa_system=capa_system or test_capa_system(render_template), capa_module=mock_capa_module()) diff --git a/common/lib/capa/capa/tests/test_capa_problem.py b/common/lib/capa/capa/tests/test_capa_problem.py index 381f0d0722..9f2888180e 100644 --- a/common/lib/capa/capa/tests/test_capa_problem.py +++ b/common/lib/capa/capa/tests/test_capa_problem.py @@ -473,7 +473,7 @@ class CAPAMultiInputProblemTest(unittest.TestCase): # verify that only one multi input group div is present at correct path multi_inputs_group = html.xpath( - '//section[@class="wrapper-problem-response"]/div[@class="multi-inputs-group"]' + '//div[@class="wrapper-problem-response"]/div[@class="multi-inputs-group"]' ) self.assertEqual(len(multi_inputs_group), 1) diff --git a/common/lib/capa/capa/tests/test_html_render.py b/common/lib/capa/capa/tests/test_html_render.py index db1527281b..c2a9491855 100644 --- a/common/lib/capa/capa/tests/test_html_render.py +++ b/common/lib/capa/capa/tests/test_html_render.py @@ -1,3 +1,7 @@ +""" +CAPA HTML rendering tests. +""" +import ddt import unittest from lxml import etree import os @@ -9,7 +13,11 @@ from .response_xml_factory import StringResponseXMLFactory, CustomResponseXMLFac from capa.tests.helpers import test_capa_system, new_loncapa_problem +@ddt.ddt class CapaHtmlRenderTest(unittest.TestCase): + """ + CAPA HTML rendering tests class. + """ def setUp(self): super(CapaHtmlRenderTest, self).setUp() @@ -142,28 +150,28 @@ class CapaHtmlRenderTest(unittest.TestCase): # Mock out the template renderer the_system = test_capa_system() the_system.render_template = mock.Mock() - the_system.render_template.return_value = "
Input Template Render
" + the_system.render_template.return_value = "
Input Template Render
" # Create the problem and render the HTML problem = new_loncapa_problem(xml_str, capa_system=the_system) rendered_html = etree.XML(problem.get_html()) - # Expect problem has been turned into a
self.assertEqual(rendered_html.tag, "div") - # Expect that the response has been turned into a
with correct attributes - response_element = rendered_html.find("section") - self.assertEqual(response_element.tag, "section") + # Expect that the response has been turned into a
with correct attributes + response_element = rendered_html.find('div') + + self.assertEqual(response_element.tag, "div") self.assertEqual(response_element.attrib["aria-label"], "Question 1") - # Expect that the response
+ # Expect that the response div.wrapper-problem-response # that contains a
for the textline - textline_element = response_element.find("div") + textline_element = response_element.find('div') self.assertEqual(textline_element.text, 'Input Template Render') # Expect a child
for the solution # with the rendered template - solution_element = rendered_html.find("div") + solution_element = rendered_html.xpath('//div[@class="input-template-render"]')[0] self.assertEqual(solution_element.text, 'Input Template Render') # Expect that the template renderer was called with the correct @@ -218,9 +226,9 @@ class CapaHtmlRenderTest(unittest.TestCase): """ problem = new_loncapa_problem(xml) rendered_html = etree.XML(problem.get_html()) - sections = rendered_html.findall('section') - self.assertEqual(sections[0].attrib['aria-label'], 'Question 1') - self.assertEqual(sections[1].attrib['aria-label'], 'Question 2') + response_elements = rendered_html.findall('div') + self.assertEqual(response_elements[0].attrib['aria-label'], 'Question 1') + self.assertEqual(response_elements[1].attrib['aria-label'], 'Question 2') def test_render_response_with_overall_msg(self): # CustomResponse script that sets an overall_message diff --git a/common/lib/capa/capa/tests/test_input_templates.py b/common/lib/capa/capa/tests/test_input_templates.py index 9c7ebf94ff..a4f8eae3dd 100644 --- a/common/lib/capa/capa/tests/test_input_templates.py +++ b/common/lib/capa/capa/tests/test_input_templates.py @@ -1181,3 +1181,43 @@ class SchematicInputTemplateTest(TemplateTestCase): Verify aria-label attribute rendering. """ self.assert_label(aria_label=True) + + +class CodeinputTemplateTest(TemplateTestCase): + """ + Test mako template for `` input + """ + + TEMPLATE_NAME = 'codeinput.html' + + def setUp(self): + super(CodeinputTemplateTest, self).setUp() + self.context = { + 'id': '1', + 'status': Status('correct'), + 'mode': 'parrot', + 'linenumbers': 'false', + 'rows': '37', + 'cols': '11', + 'tabsize': '7', + 'hidden': '', + 'msg': '', + 'value': 'print "good evening"', + 'aria_label': 'python editor', + 'code_mirror_exit_message': 'Press ESC then TAB or click outside of the code editor to exit', + 'response_data': self.RESPONSE_DATA, + 'describedby': self.DESCRIBEDBY, + } + + def test_label(self): + """ + Verify question label is rendered correctly. + """ + self.assert_label(xpath="//label[@class='problem-group-label']") + + def test_editor_exit_message(self): + """ + Verify that editor exit message is rendered. + """ + xml = self.render_to_xml(self.context) + self.assert_has_text(xml, '//span[@id="cm-editor-exit-message-1"]', self.context['code_mirror_exit_message']) diff --git a/common/lib/capa/capa/tests/test_inputtypes.py b/common/lib/capa/capa/tests/test_inputtypes.py index 01122c1df3..d94ab947ea 100644 --- a/common/lib/capa/capa/tests/test_inputtypes.py +++ b/common/lib/capa/capa/tests/test_inputtypes.py @@ -421,6 +421,8 @@ class CodeInputTest(unittest.TestCase): 'hidden': '', 'tabsize': int(tabsize), 'queue_len': '3', + 'aria_label': '{mode} editor'.format(mode=mode), + 'code_mirror_exit_message': 'Press ESC then TAB or click outside of the code editor to exit', 'response_data': RESPONSE_DATA, 'describedby_html': DESCRIBEDBY } diff --git a/common/lib/xmodule/xmodule/css/capa/display.scss b/common/lib/xmodule/xmodule/css/capa/display.scss index fa263d09e3..2e45ff8af0 100644 --- a/common/lib/xmodule/xmodule/css/capa/display.scss +++ b/common/lib/xmodule/xmodule/css/capa/display.scss @@ -908,6 +908,12 @@ div.problem { } } +.capa-message { + display: inline-block; + color: $gray-d1; + -webkit-font-smoothing: antialiased; +} + // +Problem - Actions // ==================== div.problem .action { diff --git a/common/lib/xmodule/xmodule/js/fixtures/codeinput_problem.html b/common/lib/xmodule/xmodule/js/fixtures/codeinput_problem.html new file mode 100644 index 0000000000..2f5992bac3 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/fixtures/codeinput_problem.html @@ -0,0 +1,21 @@ +
+ + + + Press ESC then TAB or click outside of the code editor to exit + + +
+ + correct + +
+
diff --git a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee index 75a40c56e0..ce50dfd0c1 100644 --- a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee @@ -834,3 +834,25 @@ describe 'Problem', -> expect(@problem.poll.calls.count()).toEqual(6) expect($('.notification-gentle-alert .notification-message').text()).toEqual("The grading process is still running. Refresh the page to see updates.") + + describe 'codeinput problem', -> + codeinputProblemHtml = readFixtures('codeinput_problem.html') + + beforeEach -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> + callback html: codeinputProblemHtml + @problem = new Problem($('.xblock-student_view')) + @problem.render(codeinputProblemHtml) + + it 'has rendered with correct a11y info', -> + CodeMirrorTextArea = $('textarea')[1] + CodeMirrorTextAreaId = 'cm-textarea-101' + + # verify that question label has correct `for` attribute value + expect($('.problem-group-label').attr('for')).toEqual(CodeMirrorTextAreaId) + + # verify that codemirror textarea has correct `id` attribute value + expect($(CodeMirrorTextArea).attr('id')).toEqual(CodeMirrorTextAreaId) + + # verify that codemirror textarea has correct `aria-describedby` attribute value + expect($(CodeMirrorTextArea).attr('aria-describedby')).toEqual('cm-editor-exit-message-101 status_101') diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee index e856aac585..f0ef87b24c 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee @@ -397,7 +397,7 @@ class @Problem labeled_status.push($(element).text()) return labeled_status - + reset: => @disableAllButtonsWhileRunning @reset_internal, false @@ -671,7 +671,7 @@ class @Problem mode = element.data("mode") linenumbers = element.data("linenums") spaces = Array(parseInt(tabsize) + 1).join(" ") - CodeMirror.fromTextArea element[0], { + CodeMirrorEditor = CodeMirror.fromTextArea element[0], { lineNumbers: linenumbers indentUnit: tabsize tabSize: tabsize @@ -688,7 +688,12 @@ class @Problem cm.replaceSelection(spaces, "end") return false } - } + } + id = element.attr("id").replace(/^input_/, "") + CodeMirrorTextArea = CodeMirrorEditor.getInputField() + CodeMirrorTextArea.setAttribute("id", "cm-textarea-#{id}") + CodeMirrorTextArea.setAttribute("aria-describedby", "cm-editor-exit-message-#{id} status_#{id}") + return CodeMirrorEditor inputtypeShowAnswerMethods: choicegroup: (element, display, answers) => diff --git a/common/test/acceptance/pages/lms/staff_view.py b/common/test/acceptance/pages/lms/staff_view.py index c87fef1d7d..8c227faecd 100644 --- a/common/test/acceptance/pages/lms/staff_view.py +++ b/common/test/acceptance/pages/lms/staff_view.py @@ -79,7 +79,7 @@ class StaffDebugPage(PageObject): url = None def is_browser_on_page(self): - return self.q(css='section.staff-modal').present + return self.q(css='.staff-modal').present def reset_attempts(self, user=None): """ diff --git a/common/test/acceptance/tests/lms/test_lms_problems.py b/common/test/acceptance/tests/lms/test_lms_problems.py index a5a00b4afa..ef1b4af535 100644 --- a/common/test/acceptance/tests/lms/test_lms_problems.py +++ b/common/test/acceptance/tests/lms/test_lms_problems.py @@ -658,7 +658,7 @@ class CAPAProblemA11yBaseTestMixin(object): # Set the scope to the problem question problem_page.a11y_audit.config.set_scope( - include=['section.wrapper-problem-response'] + include=['.wrapper-problem-response'] ) # Run the accessibility audit. diff --git a/common/test/acceptance/tests/lms/test_problem_types.py b/common/test/acceptance/tests/lms/test_problem_types.py index cc4577c5bf..7e337d3ae1 100644 --- a/common/test/acceptance/tests/lms/test_problem_types.py +++ b/common/test/acceptance/tests/lms/test_problem_types.py @@ -371,15 +371,6 @@ class ProblemTypeTestMixin(object): self.problem_page.a11y_audit.config.set_scope( include=['div#seq_content']) - self.problem_page.a11y_audit.config.set_rules({ - "ignore": [ - 'checkboxgroup', # TODO: AC-491 - 'radiogroup', # TODO: AC-491 - 'section', # TODO: AC-491 - 'label', # TODO: AC-491 - ] - }) - # Run the accessibility audit. self.problem_page.a11y_audit.check_for_accessibility_errors() @@ -422,6 +413,12 @@ class AnnotationProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): """ super(AnnotationProblemTypeTest, self).setUp(*args, **kwargs) + self.problem_page.a11y_audit.config.set_rules({ + "ignore": [ + 'label', # TODO: AC-491 + ] + }) + def answer_problem(self, correctness): """ Answer annotation problem. @@ -939,6 +936,14 @@ class RadioTextProblemTypeTest(ChoiceTextProbelmTypeTestBase, ProblemTypeTestMix """ super(RadioTextProblemTypeTest, self).setUp(*args, **kwargs) + self.problem_page.a11y_audit.config.set_rules({ + "ignore": [ + 'radiogroup', # TODO: AC-491 + 'label', # TODO: AC-491 + 'section', # TODO: AC-491 + ] + }) + class CheckboxTextProblemTypeTest(ChoiceTextProbelmTypeTestBase, ProblemTypeTestMixin): """ @@ -966,6 +971,14 @@ class CheckboxTextProblemTypeTest(ChoiceTextProbelmTypeTestBase, ProblemTypeTest """ super(CheckboxTextProblemTypeTest, self).setUp(*args, **kwargs) + self.problem_page.a11y_audit.config.set_rules({ + "ignore": [ + 'checkboxgroup', # TODO: AC-491 + 'label', # TODO: AC-491 + 'section', # TODO: AC-491 + ] + }) + class ImageProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): """ diff --git a/lms/static/sass/course/courseware/_courseware.scss b/lms/static/sass/course/courseware/_courseware.scss index 71251222b7..b213359a79 100644 --- a/lms/static/sass/course/courseware/_courseware.scss +++ b/lms/static/sass/course/courseware/_courseware.scss @@ -560,7 +560,7 @@ html.video-fullscreen { } } - section.xqa-modal, section.staff-modal, section.history-modal { + .xqa-modal, .staff-modal, .history-modal { width: 80%; height: 80%; left: left(20%); diff --git a/lms/templates/problem_ajax.html b/lms/templates/problem_ajax.html index 3137b98d24..ae55c3e3a6 100644 --- a/lms/templates/problem_ajax.html +++ b/lms/templates/problem_ajax.html @@ -1 +1 @@ -
+
diff --git a/lms/templates/problem_notifications.html b/lms/templates/problem_notifications.html index 4a0e0d6528..a4bbf35fa9 100644 --- a/lms/templates/problem_notifications.html +++ b/lms/templates/problem_notifications.html @@ -6,7 +6,7 @@ ${'' if notification_name == 'submit' else 'is-hidden' }" tabindex="-1"> - ${notification_message} + ${notification_message}
% if notification_name is 'hint': diff --git a/lms/templates/staff_problem_info.html b/lms/templates/staff_problem_info.html index 82d4cb1b0c..589c39c68b 100644 --- a/lms/templates/staff_problem_info.html +++ b/lms/templates/staff_problem_info.html @@ -31,7 +31,7 @@ ${block_content}
% endif - +
- +
- +