Update Mathjax version to include a11y

This commit is contained in:
DawoudSheraz
2018-12-04 16:29:15 +05:00
parent 8b47763543
commit bd262e000b
17 changed files with 333 additions and 28 deletions

View File

@@ -18,7 +18,7 @@ define(
window._ = _;
$script(
'//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js' +
'https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js' +
'?config=TeX-MML-AM_SVG&delayStartupUntil=configured',
'mathjax',
function() {

View File

@@ -55,7 +55,9 @@
// the option as displayed in the context menu to false.
// When upgrading to 2.6, check if this variable name changed.
window.MathJax = {
menuSettings: {CHTMLpreview: false}
menuSettings: {
CHTMLpreview: false
}
};
};
@@ -131,7 +133,7 @@
'lang_edx': 'js/src/lang_edx',
// externally hosted files
mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
'youtube': [
// youtube URL does not end in '.js'. We add '?noext' to the path so
// that require.js adds the '.js' to the query component of the URL,

View File

@@ -69,7 +69,7 @@
'domReady': 'xmodule_js/common_static/js/vendor/domReady',
'URI': 'xmodule_js/common_static/js/vendor/URI.min',
'mock-ajax': 'xmodule_js/common_static/js/vendor/mock-ajax',
mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
'youtube': '//www.youtube.com/player_api?noext',
'js/src/ajax_prefix': 'xmodule_js/common_static/js/src/ajax_prefix',
'js/spec/test_utils': 'js/spec/test_utils'

View File

@@ -48,7 +48,7 @@
'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly',
'domReady': 'xmodule_js/common_static/js/vendor/domReady',
'URI': 'xmodule_js/common_static/js/vendor/URI.min',
mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
'youtube': '//www.youtube.com/player_api?noext',
'js/src/ajax_prefix': 'xmodule_js/common_static/js/src/ajax_prefix'
},

View File

@@ -42,6 +42,14 @@ if (typeof MathJax === 'undefined') {
});
};
};
vendorScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG';
// Automatic loading of Mathjax accessibility files
window.MathJax = {
menuSettings: {
collapsible: true,
autocollapse: true,
explorer: true
}
};
vendorScript.src = 'https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js?config=TeX-MML-AM_SVG';
document.body.appendChild(vendorScript);
}

View File

@@ -482,7 +482,6 @@
this.postMathJaxProcessor(this.markdownWithHighlight(element.text()))
);
this.typesetMathJax(element);
};
DiscussionUtil.typesetMathJax = function(element) {

View File

@@ -59,13 +59,12 @@
this.renderAttrs();
this.$('span.timeago').timeago();
this.convertMath();
this.$('.post-body');
this.$('h1,h3');
return this;
};
DiscussionThreadShowView.prototype.convertMath = function() {
DiscussionUtil.convertMath(this.$('.post-body'));
DiscussionUtil.typesetMathJax(this.$('.post-body'));
};
DiscussionThreadShowView.prototype.edit = function(event) {

View File

@@ -317,7 +317,9 @@
if (options.focusAddedResponse) {
this.focusToTheAddedResponse(view.el);
}
DiscussionUtil.typesetMathJax(view.$el.find('.js-response-list'));
// Typeset the response when initially loaded for any forum
DiscussionUtil.typesetMathJax(view.$el);
return view;
};
DiscussionThreadView.prototype.renderAddResponseButton = function() {
@@ -345,7 +347,7 @@
};
DiscussionThreadView.prototype.submitComment = function(event) {
var body, comment, url;
var body, comment, url, view;
event.preventDefault();
url = this.model.urlFor('reply');
body = this.getWmdContent('reply-body');
@@ -365,7 +367,7 @@
user_id: window.user.get('id')
});
comment.set('thread', this.model.get('thread'));
this.renderResponseToList(comment, '.js-response-list', {
view = this.renderResponseToList(comment, '.js-response-list', {
focusAddedResponse: true
});
this.model.addComment();
@@ -380,7 +382,8 @@
},
success: function(data) {
comment.updateInfo(data.annotated_content_info);
return comment.set(data.content);
comment.set(data.content);
DiscussionUtil.typesetMathJax(view.$el.find('.response-body'));
}
});
};

View File

@@ -72,6 +72,7 @@
ResponseCommentShowView.prototype.convertMath = function() {
DiscussionUtil.convertMath(this.$el.find('.response-body'));
DiscussionUtil.typesetMathJax(this.$el.find('.response-body'));
};
ResponseCommentShowView.prototype._delete = function(event) {

View File

@@ -82,7 +82,7 @@
ThreadResponseView.prototype.render = function() {
this.$el.addClass('response_' + this.model.get('id'));
this.$el.html(this.renderTemplate());
edx.HtmlUtils.setHtml(this.$el, edx.HtmlUtils.HTML(this.renderTemplate()));
this.delegateEvents();
this.renderShowView();
this.renderAttrs();
@@ -309,6 +309,7 @@
event.preventDefault();
this.createShowView();
this.renderShowView();
DiscussionUtil.typesetMathJax(this.$el.find('.response-body'));
return this.showCommentForm();
};
@@ -342,6 +343,7 @@
});
self.createShowView();
self.renderShowView();
DiscussionUtil.typesetMathJax(self.$el.find('.response-body'));
return self.showCommentForm();
}
});

View File

@@ -75,9 +75,19 @@
}
</script>
<script type="text/javascript">
// Activating Mathjax accessibility files
window.MathJax = {
menuSettings: {
collapsible: true,
autocollapse: true,
explorer: true
}
};
</script>
<!-- This must appear after all mathjax-config blocks, so it is after the imports from the other templates.
It can't be run through static.url because MathJax uses crazy url introspection to do lazy loading of
MathJax extension libraries -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js?config=TeX-MML-AM_SVG"></script>
%endif

View File

@@ -727,10 +727,11 @@ class DiscussionTabHomePage(CoursePage, DiscussionPageMixin):
self.wait_for_element_visibility(selector, "WMD preview pane has contents", timeout=10)
return self.q(css=".wmd-preview").html[0]
def get_new_post_preview_text(self):
def get_new_post_preview_text(self, selector=".wmd-preview > div"):
"""
Get the rendered preview of the contents of the Discussions new post editor
Waits for content to appear, as the preview is triggered on debounced/delayed onchange
"""
self.wait_for_element_visibility(".wmd-preview > div", "WMD preview pane has contents", timeout=10)
self.scroll_to_element(selector)
self.wait_for_element_visibility(selector, "WMD preview pane has contents", timeout=10)
return self.q(css=".wmd-preview").text[0]

View File

@@ -90,6 +90,21 @@ class ProblemPage(PageObject):
description="MathJax rendered in problem body"
)
def verify_mathjax_rendered_in_preview(self):
"""
Check that MathJax has been rendered in formula problem preview
"""
def mathjax_present():
""" Returns True if MathJax css is present inside the preview """
mathjax_container = self.q(css="div.problem div .MathJax_SVG")
return mathjax_container.visible and mathjax_container.present
self.wait_for(
mathjax_present,
description="MathJax rendered in problem preview"
)
def verify_mathjax_rendered_in_hint(self):
"""
Check that MathJax have been rendered in problem hint
@@ -127,6 +142,13 @@ class ProblemPage(PageObject):
self.wait_for_element_invisibility('.loading', 'wait for loading icon to disappear')
self.wait_for_ajax()
@property
def get_numerical_input_value(self):
"""
Get the numerical problem input contents
"""
return self.q(css='div.problem div.inputtype input').text[0]
def click_submit(self):
"""
Click the Submit button.
@@ -416,6 +438,23 @@ class ProblemPage(PageObject):
"""
return self.q(css="div.problem div.inputtype div.incorrect span.status").is_present()
def get_simpleprob_correctness(self):
"""
Returns the correctness status for a simple problem.
Given a simple problem, the method returns the correctness status.
If there is no visible status, None is returned
"""
if self.simpleprob_is_correct():
return 'correct'
elif self.simpleprob_is_incorrect():
return 'incorrect'
elif self.simpleprob_is_partially_correct():
return 'partial'
else:
return None
def click_clarification(self, index=0):
"""
Click on an inline icon that can be included in problem text using an HTML <clarification> element:

View File

@@ -3,6 +3,7 @@ Tests for discussion pages
"""
import datetime
import time
from unittest import skip
from uuid import uuid4
@@ -961,6 +962,9 @@ class DiscussionEditorPreviewTest(UniqueCourseTest):
self.page.visit()
self.page.click_new_post_button()
# sleep/wait added to allow Major MathJax a11y files to load
time.sleep(5)
def test_text_rendering(self):
"""When I type plain text into the editor, it should be rendered as plain text in the preview box"""
self.page.set_new_post_editor_value("Some plain text")
@@ -999,6 +1003,21 @@ class DiscussionEditorPreviewTest(UniqueCourseTest):
)
self.assertEqual(self.page.get_new_post_preview_text(), 'Text line 1\nText line 2')
def test_inline_mathjax_rendering_in_order(self):
"""
Tests the order of Post body content when inline Mathjax is used.
With inline mathjax expressions, the text content doesn't break into new lines at the places of
mathjax expressions.
"""
self.page.set_new_post_editor_value(
'Text line 1 \n'
'$e[n]=d_1$ \n'
'Text line 2 \n'
'$e[n]=d_2$'
)
self.assertEqual(self.page.get_new_post_preview_text('.wmd-preview > p'), 'Text line 1 Text line 2')
def test_mathjax_not_rendered_after_post_cancel(self):
"""
Tests that mathjax is not rendered when we cancel the post

View File

@@ -5,6 +5,8 @@ Bok choy acceptance tests for problems in the LMS
See also old lettuce tests in lms/djangoapps/courseware/features/problems.feature
"""
from textwrap import dedent
import time
import ddt
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
@@ -933,3 +935,223 @@ class ProblemMetaUngradedTest(ProblemsTest):
problem_page = ProblemPage(self.browser)
self.assertEqual(problem_page.problem_name, 'TEST PROBLEM')
self.assertEqual(problem_page.problem_progress_graded_value, "1 point possible (ungraded)")
class FormulaProblemTest(ProblemsTest):
"""
Test Class to verify the formula problem on LMS.
"""
def setUp(self):
"""
Setup the test suite to verify various behaviors involving formula problem type.
Given a course, setup a formula problem type and view it in courseware
Given the MathJax requirement for generating preview, wait for MathJax files to load
"""
super(FormulaProblemTest, self).setUp()
self.courseware_page.visit()
time.sleep(6)
def get_problem(self):
"""
creating the formula response problem, with reset button enabled.
"""
xml = dedent("""
<problem>
<formularesponse type="ci" samples="R_1,R_2,R_3@1,2,3:3,4,5#10" answer="R_1*R_2/R_3">
<p>You can use this template as a guide to the OLX markup to use for math expression problems. Edit this component to replace the example with your own assessment.</p>
<label>Add the question text, or prompt, here. This text is required. Example: Write an expression for the product of R_1, R_2, and the inverse of R_3.</label>
<description>You can add an optional tip or note related to the prompt like this. Example: To test this example, the correct answer is R_1*R_2/R_3</description>
<responseparam type="tolerance" default="0.00001"/>
<formulaequationinput size="40"/>
</formularesponse>
</problem>
""")
return XBlockFixtureDesc('problem', 'TEST PROBLEM', data=xml, metadata={'show_reset_button': True})
def test_reset_problem_after_incorrect_submission(self):
"""
Scenario: Verify that formula problem can be resetted after an incorrect submission.
Given I am attempting a formula response problem type
When I input an incorrect answer
Then the answer preview is generated using MathJax
When I submit the problem
Then I can see incorrect status and a reset button
When I click reset, the input pane contents get clear
"""
problem_page = ProblemPage(self.browser)
problem_page.fill_answer_numerical('R_1*R_2')
problem_page.verify_mathjax_rendered_in_preview()
problem_page.click_submit()
self.assertFalse(problem_page.simpleprob_is_correct())
self.assertTrue(problem_page.is_reset_button_present())
problem_page.click_reset()
self.assertEqual(problem_page.get_numerical_input_value, '')
def test_reset_button_not_rendered_after_correct_submission(self):
"""
Scenario: Verify that formula problem can not be resetted after an incorrect submission.
Given I am attempting a formula response problem type
When I input a correct answer
Then I should be able to see the mathjax generated preview
When I submit the answer
Then the correct status is visible
And reset button is not rendered
"""
problem_page = ProblemPage(self.browser)
problem_page.fill_answer_numerical('R_1*R_2/R_3')
problem_page.verify_mathjax_rendered_in_preview()
problem_page.click_submit()
self.assertTrue(problem_page.simpleprob_is_correct())
self.assertFalse(problem_page.is_reset_button_present())
def test_reset_problem_after_changing_correctness(self):
"""
Scenario: Verify that formula problem can be resetted after changing the correctness.
Given I am attempting a formula problem type
When I answer it correctly
Then the correctness status should be visible
And reset button is not rendered
When I change my submission to incorrect
Then the reset button appears and is clickable
"""
problem_page = ProblemPage(self.browser)
problem_page.fill_answer_numerical('R_1*R_2/R_3')
problem_page.verify_mathjax_rendered_in_preview()
problem_page.click_submit()
self.assertTrue(problem_page.simpleprob_is_correct())
self.assertFalse(problem_page.is_reset_button_present())
problem_page.fill_answer_numerical('R_1/R_3')
problem_page.click_submit()
self.assertFalse(problem_page.simpleprob_is_correct())
self.assertTrue(problem_page.is_reset_button_present())
problem_page.click_reset()
self.assertEqual(problem_page.get_numerical_input_value, '')
@ddt.ddt
class FormulaProblemRandomizeTest(ProblemsTest):
"""
Test Class to verify the formula problem on LMS with Randomization enabled.
"""
def setUp(self):
"""
Setup the test suite to verify various behaviors involving formula problem type.
Given a course, setup a formula problem type and view it in courseware
Given the MathJax requirement for generating preview, wait for MathJax files to load
"""
super(FormulaProblemRandomizeTest, self).setUp()
self.courseware_page.visit()
time.sleep(6)
def get_problem(self):
"""
creating the formula response problem.
"""
xml = dedent("""
<problem>
<formularesponse type="ci" samples="R_1,R_2,R_3@1,2,3:3,4,5#10" answer="R_1*R_2/R_3">
<p>You can use this template as a guide to the OLX markup to use for math expression problems. Edit this component to replace the example with your own assessment.</p>
<label>Add the question text, or prompt, here. This text is required. Example: Write an expression for the product of R_1, R_2, and the inverse of R_3.</label>
<description>You can add an optional tip or note related to the prompt like this. Example: To test this example, the correct answer is R_1*R_2/R_3</description>
<responseparam type="tolerance" default="0.00001"/>
<formulaequationinput size="40"/>
</formularesponse>
</problem>
""")
# rerandomize:always will show reset button, no matter the submission correctness
return XBlockFixtureDesc(
'problem', 'TEST PROBLEM', data=xml, metadata={'show_reset_button': True, 'rerandomize': 'always'}
)
@ddt.data(
('R_1*R_2', 'incorrect'),
('R_1/R_3', 'incorrect'),
('R_1*R_2/R_3', 'correct')
)
@ddt.unpack
def test_reset_problem_after_submission(self, input_value, correctness):
"""
Scenario: Test that reset button works regardless the submission correctness status.
Given I am attempting a formula problem type with randomization:always configuration
When I input the answer
Then I should be able to see the MathJax generated preview
When I submit the problem
Then I should be able to see the reset button
When reset button is clicked
Then the input pane contents should be clear
"""
problem_page = ProblemPage(self.browser)
problem_page.fill_answer_numerical(input_value)
problem_page.verify_mathjax_rendered_in_preview()
problem_page.click_submit()
self.assertEqual(problem_page.get_simpleprob_correctness(), correctness)
self.assertTrue(problem_page.is_reset_button_present())
problem_page.click_reset()
self.assertEqual(problem_page.get_numerical_input_value, '')
@ddt.data(
('R_1*R_2', 'incorrect', '0/1 point (ungraded)', '0/1 point (ungraded)'),
('R_1*R_2/R_3', 'correct', '1/1 point (ungraded)', '0/1 point (ungraded)'),
('R_1/R_2', 'incorrect', '0/1 point (ungraded)', '0/1 point (ungraded)')
)
@ddt.unpack
def test_score_reset_after_resetting_problem(self, input_value, correctness, score_before_reset, score_after_reset):
"""
Scenario: Test that score resets after the formula problem is resetted.
Given I am attempting a formula problem type with randomization:always configuration
When I input the answer
Then I should be able to see the MathJax generated preview
When I submit the problem
Then I should be able to view the score that I received
And The reset button should be present and is clickable
When the reset button is clicked
Then the score resets to zero
"""
problem_page = ProblemPage(self.browser)
problem_page.fill_answer_numerical(input_value)
problem_page.verify_mathjax_rendered_in_preview()
problem_page.click_submit()
self.assertEqual(problem_page.get_simpleprob_correctness(), correctness)
self.assertIn(score_before_reset, problem_page.problem_progress_graded_value)
self.assertTrue(problem_page.is_reset_button_present())
problem_page.click_reset()
self.assertIn(score_after_reset, problem_page.problem_progress_graded_value)
@ddt.data(
('R_1*R_2', 'incorrect', 'R_1*R_2/R_3'),
('R_1*R_2/R_3', 'correct', 'R_1/R_3')
)
@ddt.unpack
def test_reset_correctness_after_changing_answer(self, input_value, correctness, next_input):
"""
Scenario: Test that formula problem can be resetted after changing the answer.
Given I am attempting a formula problem type with randomization:always configuration
When I input an answer
Then the mathjax generated preview should be visible
When I submit the problem, I can see the correctness status
When I only input another answer
Then the correctness status is no longer visible
And I am able to see the reset button
And when I click the reset button
Then input pane contents are cleared
"""
problem_page = ProblemPage(self.browser)
problem_page.fill_answer_numerical(input_value)
problem_page.verify_mathjax_rendered_in_preview()
problem_page.click_submit()
self.assertEqual(problem_page.get_simpleprob_correctness(), correctness)
problem_page.fill_answer_numerical(next_input)
self.assertIsNone(problem_page.get_simpleprob_correctness())
self.assertTrue(problem_page.is_reset_button_present())
problem_page.click_reset()
self.assertEqual(problem_page.get_numerical_input_value, '')

View File

@@ -22,8 +22,8 @@ Feature: LMS.Answer problems
| radio | correct | always |
| radio | incorrect | always |
| numerical | incorrect | always |
| formula | correct | always |
| formula | incorrect | always |
#| formula | correct | always |
#| formula | incorrect | always |
| script | correct | always |
| script | incorrect | always |
| radio_text | correct | always |
@@ -49,7 +49,7 @@ Feature: LMS.Answer problems
#| radio | incorrect | never |
#| string | incorrect | never |
| numerical | incorrect | never |
| formula | incorrect | never |
#| formula | incorrect | never |
# TE-572 failing intermittently
#| script | incorrect | never |
| radio_text | incorrect | never |
@@ -69,7 +69,7 @@ Feature: LMS.Answer problems
| radio | correct | never |
#| string | correct | never |
| numerical | correct | never |
| formula | correct | never |
#| formula | correct | never |
| script | correct | never |
| radio_text | correct | never |
| checkbox_text | correct | never |
@@ -129,8 +129,8 @@ Feature: LMS.Answer problems
| radio | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) |
| numerical | correct | 1/1 point (ungraded) | 0/1 point (ungraded) |
| numerical | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) |
| formula | correct | 1/1 point (ungraded) | 0/1 point (ungraded) |
| formula | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) |
#| formula | correct | 1/1 point (ungraded) | 0/1 point (ungraded) |
#| formula | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) |
| script | correct | 2/2 points (ungraded) | 0/2 points (ungraded) |
| script | incorrect | 0/2 points (ungraded) | 0/2 points (ungraded) |
| image | correct | 1/1 point (ungraded) | 0/1 point (ungraded) |
@@ -155,8 +155,8 @@ Feature: LMS.Answer problems
| radio | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) | never |
| numerical | correct | 1/1 point (ungraded) | 0/1 point (ungraded) | never |
| numerical | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) | never |
| formula | correct | 1/1 point (ungraded) | 0/1 point (ungraded) | never |
| formula | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) | never |
#| formula | correct | 1/1 point (ungraded) | 0/1 point (ungraded) | never |
#| formula | incorrect | 0/1 point (ungraded) | 0/1 point (ungraded) | never |
| script | correct | 2/2 points (ungraded) | 0/2 points (ungraded) | never |
| script | incorrect | 0/2 points (ungraded) | 0/2 points (ungraded) | never |
| image | correct | 1/1 point (ungraded) | 0/1 point (ungraded) | never |
@@ -189,8 +189,8 @@ Feature: LMS.Answer problems
#| string | incorrect | correct |
| numerical | correct | incorrect |
| numerical | incorrect | correct |
| formula | correct | incorrect |
| formula | incorrect | correct |
#| formula | correct | incorrect |
#| formula | incorrect | correct |
| script | correct | incorrect |
| script | incorrect | correct |

View File

@@ -56,7 +56,7 @@
'squire': 'common/js/vendor/Squire',
'jasmine-imagediff': 'xmodule_js/common_static/js/vendor/jasmine-imagediff',
'domReady': 'xmodule_js/common_static/js/vendor/domReady',
mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@2.7.5/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
'youtube': '//www.youtube.com/player_api?noext',
'js/src/ajax_prefix': 'xmodule_js/common_static/js/src/ajax_prefix',
'js/instructor_dashboard/student_admin': 'js/instructor_dashboard/student_admin',