Commit 7240b625 by muhammad-ammar Committed by muzaffaryousaf

Associate descriptions with question text

TNL-5014
parent 3556f2a3
......@@ -13,6 +13,7 @@ Main module which shows problems (of "capa" type).
This is used by capa_module.
"""
from collections import OrderedDict
from copy import deepcopy
from datetime import datetime
import logging
......@@ -35,6 +36,16 @@ from capa.safe_exec import safe_exec
# extra things displayed after "show answers" is pressed
solution_tags = ['solution']
# fully accessible capa response types
ACCESSIBLE_CAPA_RESPONSE_TYPES = [
'choiceresponse',
'multiplechoiceresponse',
'optionresponse',
'numericalresponse',
'stringresponse',
'formularesponse',
]
# these get captured as student responses
response_properties = ["codeparam", "responseparam", "answer", "openendedparam"]
......@@ -61,6 +72,8 @@ log = logging.getLogger(__name__)
#-----------------------------------------------------------------------------
# main class for this module
DEFAULT_QUESTION_TEXT = "Formatting error: You must explicitly specify the question text."
class LoncapaSystem(object):
"""
......@@ -855,17 +868,76 @@ class LoncapaProblem(object):
id=response_id_str
)
# assign one answer_id for each input type or solution type
# assign one answer_id for each input type
for entry in inputfields:
entry.attrib['response_id'] = str(response_id)
entry.attrib['answer_id'] = str(answer_id)
entry.attrib['id'] = "%s_%i_%i" % (self.problem_id, response_id, answer_id)
answer_id = answer_id + 1
# Find the label and save it for html transformation step
responsetype_label = response.find('label')
problem_data[self.problem_id + '_' + str(response_id)] = {
'label': responsetype_label.text if responsetype_label is not None else ''
question_id = u'{}_{}'.format(self.problem_id, response_id)
label = ''
element_to_be_deleted = None
# Extract label value from <label> tag or label attribute from inside the responsetype
responsetype_label_tag = response.find('label')
if responsetype_label_tag is not None:
label = responsetype_label_tag.text
# store <label> tag containing question text to delete
# it later otherwise question will be rendered twice
element_to_be_deleted = responsetype_label_tag
elif 'label' in inputfields[0].attrib:
# Extract label value from label attribute
# This is the case when we have a problem
# * with multiple questions without separation
# * single question with old XML format only
label = inputfields[0].attrib['label']
# Get first <p> tag before responsetype, this <p> contains the question text.
p_tag = response.xpath('preceding-sibling::p[1]')
if p_tag:
# It may be possible that label attribute value doesn't match with <p> tag
# This happens when author updated the question <p> tag directly in XML but
# didn't changed the label attribute value. In this case we will consider the
# first <p> tag before responsetype as question.
if label != p_tag[0].text:
label = p_tag[0].text
element_to_be_deleted = p_tag[0]
else:
# In this case the problems don't have tag or label attribute inside the responsetype
# so we will get the first preceding label tag w.r.t to this responsetype.
# This will take care of those multi-question problems that are not using --- in their markdown.
label_tag = response.xpath("preceding-sibling::label[1]")
if label_tag:
label = label_tag[0].text
element_to_be_deleted = label_tag[0]
label = label.strip() or DEFAULT_QUESTION_TEXT
# delete label or p element only if responsetype is fully accessible
if response.tag in ACCESSIBLE_CAPA_RESPONSE_TYPES and element_to_be_deleted is not None:
element_to_be_deleted.getparent().remove(element_to_be_deleted)
# for non-accessible responsetypes it may be possible that label attribute is not present
# in this case pass an empty label. remember label attribute is only used as value for aria-label
if response.tag not in ACCESSIBLE_CAPA_RESPONSE_TYPES and label == DEFAULT_QUESTION_TEXT:
label = ''
# Extract descriptions and set unique id on each description tag
description_tags = response.findall('description')
description_id = 1
descriptions = OrderedDict()
for description in description_tags:
descriptions[
"description_%s_%i_%i" % (self.problem_id, response_id, description_id)
] = description.text
response.remove(description)
description_id += 1
problem_data[question_id] = {
'label': label,
'descriptions': descriptions
}
# instantiate capa Response
......
......@@ -225,7 +225,7 @@ class InputTypeBase(object):
self.hintmode = feedback.get('hintmode', None)
self.input_state = state.get('input_state', {})
self.answervariable = state.get('answervariable', None)
self.response_data = state.get('response_data', None)
self.response_data = state.get('response_data')
# put hint above msg if it should be displayed
if self.hintmode == 'always':
......@@ -319,8 +319,16 @@ class InputTypeBase(object):
'msg': self.msg,
'response_data': self.response_data,
'STATIC_URL': self.capa_system.STATIC_URL,
'describedby': '',
}
# Don't add aria-describedby attribute if there are no descriptions
if self.response_data.get('descriptions'):
description_ids = ' '.join(self.response_data.get('descriptions').keys())
context.update(
{'describedby': 'aria-describedby="{}"'.format(description_ids)}
)
context.update(
(a, v) for (a, v) in self.loaded_attributes.iteritems() if a in self.to_render
)
......@@ -380,7 +388,7 @@ class OptionInput(InputTypeBase):
Example:
<optioninput options="('Up','Down')" label="Where is the sky?" correct="Up"/><text>The location of the sky</text>
<optioninput options="('Up','Down')" correct="Up"/><text>The location of the sky</text>
# TODO: allow ordering to be randomized
"""
......@@ -416,7 +424,6 @@ class OptionInput(InputTypeBase):
Convert options to a convenient format.
"""
return [Attribute('options', transform=cls.parse_options),
Attribute('label', ''),
Attribute('inline', False)]
#-----------------------------------------------------------------------------
......@@ -435,7 +442,7 @@ class ChoiceGroup(InputTypeBase):
Example:
<choicegroup label="Which foil?">
<choicegroup>
<choice correct="false" name="foil1">
<text>This is foil One.</text>
</choice>
......@@ -478,7 +485,6 @@ class ChoiceGroup(InputTypeBase):
# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
_ = lambda text: text
return [Attribute("show_correctness", "always"),
Attribute('label', ''),
Attribute("submitted_message", _("Answer received."))]
def _extra_context(self):
......@@ -640,7 +646,7 @@ class TextLine(InputTypeBase):
is used e.g. for embedding simulations turned into questions.
Example:
<textline math="1" trailing_text="m/s" label="How fast is a cheetah?" />
<textline math="1" trailing_text="m/s"/>
This example will render out a text line with a math preview and the text 'm/s'
after the end of the text line.
......@@ -656,7 +662,6 @@ class TextLine(InputTypeBase):
"""
return [
Attribute('size', None),
Attribute('label', ''),
Attribute('hidden', False),
Attribute('inline', False),
......@@ -716,7 +721,6 @@ class FileSubmission(InputTypeBase):
Convert the list of allowed files to a convenient format.
"""
return [Attribute('allowed_files', '[]', transform=cls.parse_files),
Attribute('label', ''),
Attribute('required_files', '[]', transform=cls.parse_files), ]
def setup(self):
......@@ -1030,7 +1034,6 @@ class Schematic(InputTypeBase):
Attribute('analyses', None),
Attribute('initial_value', None),
Attribute('submit_analyses', None),
Attribute('label', ''),
]
def _extra_context(self):
......@@ -1066,7 +1069,6 @@ class ImageInput(InputTypeBase):
"""
return [Attribute('src'),
Attribute('height'),
Attribute('label', ''),
Attribute('width'), ]
def setup(self):
......@@ -1157,8 +1159,7 @@ class ChemicalEquationInput(InputTypeBase):
"""
Can set size of text field.
"""
return [Attribute('size', '20'),
Attribute('label', ''), ]
return [Attribute('size', '20'), ]
def _extra_context(self):
"""
......@@ -1221,7 +1222,7 @@ class FormulaEquationInput(InputTypeBase):
Example:
<formulaequationinput size="50" label="Enter the equation for motion" />
<formulaequationinput size="50"/>
options: size -- width of the textbox.
trailing_text -- text to show after the input textbox when
......@@ -1239,7 +1240,6 @@ class FormulaEquationInput(InputTypeBase):
return [
Attribute('size', '20'),
Attribute('inline', False),
Attribute('label', ''),
Attribute('trailing_text', ''),
]
......@@ -1629,7 +1629,7 @@ class ChoiceTextGroup(InputTypeBase):
select the correct choice and fill in numbers to make it accurate.
<endouttext/>
<choicetextresponse>
<radiotextgroup label="What is the correct choice?">
<radiotextgroup>
<choice correct="false">The lowest number rolled was:
<decoy_input/> and the highest number rolled was:
<decoy_input/> .</choice>
......@@ -1652,7 +1652,7 @@ class ChoiceTextGroup(InputTypeBase):
select the correct choices and fill in numbers to make them accurate.
<endouttext/>
<choicetextresponse>
<checkboxtextgroup label="What is the answer?">
<checkboxtextgroup>
<choice correct="true">
The lowest number selected was <numtolerance_input answer="1.4142" tolerance="0.01"/>
</choice>
......@@ -1718,7 +1718,6 @@ class ChoiceTextGroup(InputTypeBase):
return [
Attribute("show_correctness", "always"),
Attribute("submitted_message", _("Answer received.")),
Attribute("label", ""),
]
def _extra_context(self):
......
......@@ -3,7 +3,7 @@
<div class="${status.classname}" id="status_${id}">
<input type="text" name="input_${id}" id="input_${id}" aria-label="${label}" aria-describedby="answer_${id}" data-input-id="${id}" value="${value|h}"
<input type="text" name="input_${id}" id="input_${id}" aria-label="${response_data['label']}" aria-describedby="answer_${id}" data-input-id="${id}" value="${value|h}"
% if size:
size="${size}"
% endif
......
......@@ -5,12 +5,11 @@
))
%>
<form class="choicegroup capa_inputtype" id="inputtype_${id}">
<fieldset>
% if response_data and response_data['label']:
<legend id="${id}-legend" class="response-fieldset-legend question-text">${response_data['label']}</legend>
% else:
<legend>Question</legend>
% endif
<fieldset ${describedby}>
<legend id="${id}-legend" class="response-fieldset-legend field-group-hd">${response_data['label']}</legend>
% for description_id, description_text in response_data['descriptions'].items():
<p class="question-description" id="${description_id}">${description_text}</p>
% endfor
% for choice_id, choice_label in choices:
<div class="field" aria-live="polite" aria-atomic="true">
<%
......@@ -33,8 +32,9 @@
<% label_class += ' choicegroup_' + correctness %>
% endif
% endif
class="${label_class}" >
class="${label_class}"
${describedby}
>
<input type="${input_type}" name="input_${id}${name_array_suffix}" id="input_${id}_${choice_id}" class="field-input input-${input_type}" value="${choice_id}"
## If the student selected this choice...
% if is_radio_input(choice_id):
......
......@@ -9,8 +9,8 @@
<section id="choicetextinput_${id}" class="choicetextinput">
<form class="choicetextgroup capa_inputtype" id="inputtype_${id}">
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/choicetextinput.js"/>
<fieldset aria-label="${label}">
<fieldset aria-label="${response_data['label']}">
% for choice_id, choice_description in choices:
<%choice_id= choice_id %>
<section id="forinput${choice_id}"
......@@ -59,7 +59,7 @@
<span id="answer_${id}"></span>
</fieldset>
<input class= "choicetextvalue" type="hidden" name="input_${id}{}" id="input_${id}" value="${value|h}" />
<div class="indicator-container">
% if input_type == 'checkbox' or not element_checked:
<span class="status ${status.classname}" id="status_${id}"></span>
......
......@@ -7,7 +7,7 @@
% endif
<p class="debug">${status}</p>
<input type="file" name="input_${id}" id="input_${id}" value="${value}" multiple="multiple" data-required_files="${required_files|h}" data-allowed_files="${allowed_files|h}" aria-label="${label}" />
<input type="file" name="input_${id}" id="input_${id}" value="${value}" multiple="multiple" data-required_files="${required_files|h}" data-allowed_files="${allowed_files|h}" aria-label="${response_data['label']}"/>
</div>
<div class="message">${msg|n}</div>
</section>
......@@ -5,8 +5,7 @@
<div class="${status.classname}" id="status_${id}">
<input type="text" name="input_${id}" id="input_${id}"
data-input-id="${id}" value="${value}"
aria-label="${label}"
aria-describedby="${id}_status"
${describedby}
% if size:
size="${size}"
% endif
......
<% doinline = "inline" if inline else "" %>
<form class="inputtype option-input ${doinline}">
<select name="input_${id}" id="input_${id}" aria-label="${label}" aria-describedby="answer_${id}">
<select name="input_${id}" id="input_${id}" aria-label="${response_data['label']}" ${describedby}>
<option value="option_${id}_dummy_default"> </option>
% for option_id, option_description in options:
<option value="${option_id}"
......
......@@ -8,7 +8,7 @@
analyses="${analyses}"
name="input_${id}"
id="input_${id}"
aria-label="${label}"
aria-label="${response_data['label']}"
aria-describedby="answer_${id}"
value="${value|h}"
initial_value="${initial_value|h}"
......
......@@ -16,7 +16,7 @@
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
<input type="text" name="input_${id}" id="input_${id}" aria-label="${label}" aria-describedby="answer_${id}" value="${value}"
<input type="text" name="input_${id}" id="input_${id}" aria-label="${response_data['label']}" ${describedby} value="${value}"
% if do_math:
class="math"
% endif
......@@ -29,15 +29,15 @@
/>
<span class="trailing_text">${trailing_text}</span>
<span class="status"
<span class="status"
%if status != 'unsubmitted':
%endif
aria-describedby="input_${id}" data-tooltip="${status.display_tooltip}">
<span class="sr">
%if value:
${value}
% else:
${label}
%else:
${response_data['label']}
%endif
-
${status.display_name}
......
"""
Test capa problem.
"""
import unittest
from . import new_loncapa_problem
from capa.capa_problem import DEFAULT_QUESTION_TEXT
class CAPAProblemTest(unittest.TestCase):
""" CAPA problem related tests"""
def test_label_and_description_inside_responsetype(self):
"""
Verify that
* label is extracted
* <label> tag is removed to avoid duplication
This is the case when we have a problem with single question or
problem with multiple-questions separated as per the new format.
"""
xml = """
<problem>
<choiceresponse>
<label>Select the correct synonym of paranoid?</label>
<description>Only the paranoid survive.</description>
<checkboxgroup>
<choice correct="true">over-suspicious</choice>
<choice correct="false">funny</choice>
</checkboxgroup>
</choiceresponse>
</problem>
"""
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': 'Select the correct synonym of paranoid?',
'descriptions': {'description_1_2_1': 'Only the paranoid survive.'}
}
}
)
self.assertEqual(len(problem.tree.xpath('//label')), 0)
def test_label_attribute_only(self):
"""
Verify that label is extracted and <p> tag with question
text is removed when label attribute is set on inputtype.
"""
question = "Once we become predictable, we become ______?"
xml = """
<problem>
<p>Be sure to check your spelling.</p>
<p>{}</p>
<stringresponse answer="vulnerable" type="ci">
<textline label="{}" size="40"/>
</stringresponse>
</problem>
""".format(question, question)
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{'1_2': {'label': question, 'descriptions': {}}}
)
self.assertEqual(
len(problem.tree.xpath('//p[text()="{}"]'.format(question))),
0
)
def test_neither_label_tag_nor_attribute(self):
"""
Verify that label is extracted correctly.
This is the case when we have a markdown problem with multiple-questions.
In this case when markdown is converted to xml, there will be no label
tag and label attribute inside responsetype. But we have a label tag
before the responsetype.
"""
question1 = 'People who say they have nothing to ____ almost always do?'
question2 = 'Select the correct synonym of paranoid?'
xml = """
<problem>
<p>Be sure to check your spelling.</p>
<label>{}</label>
<stringresponse answer="hide" type="ci">
<textline size="40"/>
</stringresponse>
<choiceresponse>
<label>{}</label>
<checkboxgroup>
<choice correct="true">over-suspicious</choice>
<choice correct="false">funny</choice>
</checkboxgroup>
</choiceresponse>
</problem>
""".format(question1, question2)
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': question1,
'descriptions': {}
},
'1_3':
{
'label': question2,
'descriptions': {}
}
}
)
for question in (question1, question2):
self.assertEqual(
len(problem.tree.xpath('//label[text()="{}"]'.format(question))),
0
)
def test_multiple_descriptions(self):
"""
Verify that multiple descriptions are handled correctly.
"""
xml = """
<problem>
<p>Be sure to check your spelling.</p>
<stringresponse answer="War" type="ci">
<label>___ requires sacrifices.</label>
<description>The problem with trying to be the bad guy, there's always someone worse.</description>
<description>Anyone who looks the world as if it was a game of chess deserves to lose.</description>
<textline size="40"/>
</stringresponse>
</problem>
"""
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': '___ requires sacrifices.',
'descriptions': {
'description_1_2_1': "The problem with trying to be the bad guy, there's always someone worse.",
'description_1_2_2': "Anyone who looks the world as if it was a game of chess deserves to lose."
}
}
}
)
def test_default_question_text(self):
"""
Verify that default question text is shown when question is missing.
"""
xml = """
<problem>
<p>Be sure to check your spelling.</p>
<stringresponse answer="War" type="ci">
<description>Everybody needs somebody to talk to.</description>
<textline size="40"/>
</stringresponse>
</problem>
"""
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': DEFAULT_QUESTION_TEXT,
'descriptions': {
'description_1_2_1': "Everybody needs somebody to talk to."
}
}
}
)
def test_question_is_not_removed(self):
"""
Verify that tag with question text is not removed when responsetype is not fully accessible.
"""
question = "Click the country which is home to the Pyramids."
xml = """
<problem>
<p>{}</p>
<imageresponse>
<imageinput label="{}"
src="/static/Africa.png" width="600" height="638" rectangle="(338,98)-(412,168)"/>
</imageresponse>
</problem>
""".format(question, question)
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': 'Click the country which is home to the Pyramids.',
'descriptions': {}
}
}
)
# <p> tag with question text should not be deleted
self.assertEqual(problem.tree.xpath("string(p[text()='{}'])".format(question)), question)
def test_label_is_empty_if_no_label_attribute(self):
"""
Verify that label in response_data is empty string when label
attribute is missing and responsetype is not fully accessible.
"""
question = "Click the country which is home to the Pyramids."
xml = """
<problem>
<p>{}</p>
<imageresponse>
<imageinput
src="/static/Africa.png" width="600" height="638" rectangle="(338,98)-(412,168)"/>
</imageresponse>
</problem>
""".format(question)
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': '',
'descriptions': {}
}
}
)
def test_multiple_questions_problem(self):
"""
For a problem with multiple questions verify that for each question
* label is extracted
* descriptions info is constructed
* <label> tag is removed to avoid duplication
"""
xml = """
<problem>
<choiceresponse>
<label>Select the correct synonym of paranoid?</label>
<description>Only the paranoid survive.</description>
<checkboxgroup>
<choice correct="true">over-suspicious</choice>
<choice correct="false">funny</choice>
</checkboxgroup>
</choiceresponse>
<multiplechoiceresponse>
<p>one more question</p>
<label>What Apple device competed with the portable CD player?</label>
<description>Device looks like an egg plant.</description>
<choicegroup type="MultipleChoice">
<choice correct="false">The iPad</choice>
<choice correct="false">Napster</choice>
<choice correct="true">The iPod</choice>
<choice correct="false">The vegetable peeler</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>
"""
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': 'Select the correct synonym of paranoid?',
'descriptions': {'description_1_2_1': 'Only the paranoid survive.'}
},
'1_3':
{
'label': 'What Apple device competed with the portable CD player?',
'descriptions': {'description_1_3_1': 'Device looks like an egg plant.'}
}
}
)
self.assertEqual(len(problem.tree.xpath('//label')), 0)
def test_label_attribute_mismatches_question_tag(self):
"""
Verify that question text is extracted correctly when label attribtue value
mismatched with question tag value.
This is the case when author updated the question <p> tag directly in XML but
didn't change the label attribute value. In this case we will consider the
first <p> tag before responsetype as question.
"""
question = 'Select the correct synonym of paranoid?'
xml = """
<problem>
<p>Choose wisely.</p>
<p>{}</p>
<choiceresponse>
<checkboxgroup label="Is egg plant a fruit?">
<choice correct="true">over-suspicious</choice>
<choice correct="false">funny</choice>
</checkboxgroup>
</choiceresponse>
</problem>
""".format(question)
problem = new_loncapa_problem(xml)
self.assertEqual(
problem.problem_data,
{
'1_2':
{
'label': question,
'descriptions': {}
}
}
)
self.assertEqual(
len(problem.tree.xpath('//p[text()="{}"]'.format(question))),
0
)
<problem>
<p>Select all the fruits from the list. In retrospect, the wordiness of these tests increases the dizziness!</p>
<p>In retrospect, the wordiness of these tests increases the dizziness!</p>
<choiceresponse>
<checkboxgroup label="Select all the fruits from the list">
<label>Select all the fruits from the list</label>
<checkboxgroup>
<choice correct="true" id="alpha">Apple
<choicehint selected="TrUe">You are right that apple is a fruit.
</choicehint>
......@@ -33,9 +34,10 @@
</compoundhint>
</checkboxgroup>
</choiceresponse>
<p>Select all the vegetables from the list</p>
<choiceresponse>
<checkboxgroup label="Select all the vegetables from the list">
<label>Select all the vegetables from the list</label>
<checkboxgroup>
<choice correct="false">Banana
<choicehint selected="true">No, sorry, a banana is a fruit.
</choicehint>
......@@ -52,11 +54,11 @@
<choice correct="true">
Brussel Sprout
<choicehint selected="true">
Brussel sprouts are vegetables.
</choicehint>
<choicehint selected="false">
Brussel sprout is the only vegetable in this list.
</choicehint>
</choice>
......@@ -66,6 +68,7 @@
</compoundhint>
</checkboxgroup>
</choiceresponse>
<p>Compoundhint vs. correctness</p>
<choiceresponse>
<checkboxgroup>
......@@ -80,17 +83,17 @@
<choiceresponse>
<checkboxgroup>
<choice correct="true">
A
A
<choicehint selected="true" label="AA">
aa
</choicehint></choice>
<choice correct="true">
B <choicehint selected="false" label="BB">
bb
</choicehint></choice>
</checkboxgroup>
</choiceresponse>
......@@ -114,4 +117,3 @@
</problem>
<problem>
<p>(note the blank line before mushroom -- be sure to include this test case)</p>
<p>Select the fruit from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the fruit from the list" type="MultipleChoice">
<label>Select the fruit from the list</label>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint label="">Mushroom is a fungus, not a fruit.
</choicehint>
......@@ -14,9 +14,10 @@
</choice>
</choicegroup>
</multiplechoiceresponse>
<p>Select the vegetables from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the vegetables from the list" type="MultipleChoice">
<label>Select the vegetables from the list</label>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint>Mushroom is a fungus, not a vegetable.
</choicehint>
......
<problem>
<p>Select the fruit from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the fruit from the list" type="MultipleChoice">
<label>Select the fruit from the list</label>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint>Mushroom <img src="#" ale="#"/>is a fungus, not a fruit.</choicehint>
</choice>
......
<problem>
<numericalresponse answer="1.141">
<label>What value when squared is approximately equal to 2 (give your answer to 2 decimal places)?</label>
<responseparam default=".01" type="tolerance"/>
<formulaequationinput label="What value when squared is approximately equal to 2 (give your answer to 2 decimal places)?"/>
<formulaequationinput/>
<correcthint label="Nice">
The square root of two turns up in the strangest places.
......@@ -11,8 +12,9 @@
</numericalresponse>
<numericalresponse answer="4">
<label>What is 2 + 2?</label>
<responseparam default=".01" type="tolerance"/>
<formulaequationinput label="What is 2 + 2?"/>
<formulaequationinput/>
<correcthint>
Pretty easy, uh?.
</correcthint>
......@@ -34,4 +36,3 @@ also not multiple correcthint
</lehint>
-->
</problem>
......@@ -2,7 +2,8 @@
<p>In which country would you find the city of Paris?</p>
<stringresponse answer="FranceΩ" type="ci" >
<textline label="In which country would you find the city of Paris?" size="20"/>
<label>In which country would you find the city of Paris?</label>
<textline size="20"/>
<correcthint>
Viva la France!Ω
</correcthint>
......@@ -22,16 +23,18 @@
<p>What color is the sky? A minimal example, case sensitive, not regex.</p>
<stringresponse answer="Blue">
<label>What color is the sky?</label>
<correcthint >The red light is scattered by water molecules leaving only blue light.
</correcthint>
<textline label="What color is the sky?" size="20"/>
<textline size="20"/>
</stringresponse>
<p>(This question will cause an illegal regular expression exception)</p>
<stringresponse answer="Bonk">
<label>Why not?</label>
<correcthint >This hint should never appear.
</correcthint>
<textline label="Why not?" size="20"/>
<textline size="20"/>
<regexphint answer="[">
This hint should never appear either because the regex is illegal.
</regexphint>
......@@ -56,7 +59,7 @@
<regexphint answer="FG+"> hint6 </regexphint>
<textline size="20"/>
</stringresponse>
<!-- backward compatibility for additional_answer: old and new format together in
a problem, scored correclty and new style has a hint -->
<stringresponse answer="A">
......
<problem>
<choiceresponse>
<checkboxgroup label="Select all the vegetables from the list">
<label>Select all the vegetables from the list</label>
<checkboxgroup>
<choice correct="false">Banana
<choicehint selected="true">No, sorry, a banana is a fruit.
</choicehint>
......
......@@ -7,6 +7,7 @@ import mock
from .response_xml_factory import StringResponseXMLFactory, CustomResponseXMLFactory
from . import test_capa_system, new_loncapa_problem
from capa.capa_problem import DEFAULT_QUESTION_TEXT
class CapaHtmlRenderTest(unittest.TestCase):
......@@ -176,7 +177,6 @@ class CapaHtmlRenderTest(unittest.TestCase):
expected_textline_context = {
'STATIC_URL': '/dummy-static/',
'status': the_system.STATUS_CLASS('unsubmitted'),
'label': '',
'value': '',
'preprocessor': None,
'msg': '',
......@@ -186,6 +186,8 @@ class CapaHtmlRenderTest(unittest.TestCase):
'id': '1_2_1',
'trailing_text': '',
'size': None,
'response_data': {'label': DEFAULT_QUESTION_TEXT, 'descriptions': {}},
'describedby': ''
}
expected_solution_context = {'id': '1_solution_1'}
......
......@@ -2,6 +2,7 @@
Tests for the logic in input type mako templates.
"""
from collections import OrderedDict
import unittest
import capa
import os.path
......@@ -29,6 +30,13 @@ class TemplateTestCase(unittest.TestCase):
# The template name should include the .html extension:
# for example: choicegroup.html
TEMPLATE_NAME = None
DESCRIBEDBY = 'aria-describedby="desc-1 desc-2"'
DESCRIPTIONS = OrderedDict([('desc-1', 'description text 1'), ('desc-2', 'description text 2')])
DESCRIPTION_IDS = ' '.join(DESCRIPTIONS.keys())
RESPONSE_DATA = {
'label': 'question text 101',
'descriptions': DESCRIPTIONS
}
def setUp(self):
"""
......@@ -42,6 +50,8 @@ class TemplateTestCase(unittest.TestCase):
with open(self.template_path) as f:
self.template = MakoTemplate(f.read())
self.context = {}
def render_to_xml(self, context_dict):
"""
Render the template using the `context_dict` dict.
......@@ -112,6 +122,49 @@ class TemplateTestCase(unittest.TestCase):
else:
self.assertIn(text, element_list[0].text)
def assert_description(self, describedby_xpaths, descriptions=True):
"""
Verify that descriptions information is correct.
Arguments:
describedby_xpaths (list): list of xpaths to check aria-describedby attribute
descriptions (bool): tells whether we need to check description <p> tags
"""
xml = self.render_to_xml(self.context)
# TODO! This check should be removed once description <p> tags are added into all templates.
if descriptions:
# Verify that each description <p> tag has correct id, text and order
descriptions = OrderedDict(
(tag.get('id'), tag.text) for tag in xml.xpath('//p[@class="question-description"]')
)
self.assertEqual(self.DESCRIPTIONS, descriptions)
# for each xpath verify that description_ids are set correctly
for describedby_xpath in describedby_xpaths:
describedbys = xml.xpath(describedby_xpath)
# aria-describedby attributes must have ids
self.assertTrue(describedbys)
for describedby in describedbys:
self.assertEqual(describedby, self.DESCRIPTION_IDS)
def assert_describedby_attribute(self, describedby_xpaths):
"""
Verify that an element has no aria-describedby attribute if there are no descriptions.
Arguments:
describedby_xpaths (list): list of xpaths to check aria-describedby attribute
"""
self.context['describedby'] = ''
xml = self.render_to_xml(self.context)
# for each xpath verify that description_ids are set correctly
for describedby_xpath in describedby_xpaths:
describedbys = xml.xpath(describedby_xpath)
self.assertFalse(describedbys)
class ChoiceGroupTemplateTest(TemplateTestCase):
"""
......@@ -121,18 +174,18 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'choicegroup.html'
def setUp(self):
super(ChoiceGroupTemplateTest, self).setUp()
choices = [('1', 'choice 1'), ('2', 'choice 2'), ('3', 'choice 3')]
self.context = {
'id': '1',
'choices': choices,
'status': Status('correct'),
'label': 'test',
'input_type': 'checkbox',
'name_array_suffix': '1',
'value': '3',
'response_data': {'label': 'test'}
'response_data': self.RESPONSE_DATA,
'describedby': self.DESCRIBEDBY,
}
super(ChoiceGroupTemplateTest, self).setUp()
def test_problem_marked_correct(self):
"""
......@@ -344,7 +397,15 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
def test_label(self):
xml = self.render_to_xml(self.context)
xpath = "//legend"
self.assert_has_text(xml, xpath, self.context['label'])
self.assert_has_text(xml, xpath, self.context['response_data']['label'])
def test_description(self):
"""
Test that correct description information is set on desired elements.
"""
xpaths = ['//fieldset/@aria-describedby', '//label/@aria-describedby']
self.assert_description(xpaths)
self.assert_describedby_attribute(xpaths)
class TextlineTemplateTest(TemplateTestCase):
......@@ -355,13 +416,16 @@ class TextlineTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'textline.html'
def setUp(self):
self.context = {'id': '1',
'status': Status('correct'),
'label': 'test',
'value': '3',
'preprocessor': None,
'trailing_text': None}
super(TextlineTemplateTest, self).setUp()
self.context = {
'id': '1',
'status': Status('correct'),
'value': '3',
'preprocessor': None,
'trailing_text': None,
'response_data': self.RESPONSE_DATA,
'describedby': self.DESCRIBEDBY,
}
def test_section_class(self):
cases = [({}, ' capa_inputtype textline'),
......@@ -397,7 +461,7 @@ class TextlineTemplateTest(TemplateTestCase):
def test_label(self):
xml = self.render_to_xml(self.context)
xpath = "//input[@aria-label='%s']" % self.context['label']
xpath = "//input[@aria-label='%s']" % self.context['response_data']['label']
self.assert_has_xpath(xml, xpath, self.context)
def test_hidden(self):
......@@ -473,6 +537,14 @@ class TextlineTemplateTest(TemplateTestCase):
xpath = "//span[@class='message']"
self.assert_has_text(xml, xpath, self.context['msg'])
def test_description(self):
"""
Test that correct description information is set on desired elements.
"""
xpaths = ['//input/@aria-describedby']
self.assert_description(xpaths, descriptions=False)
self.assert_describedby_attribute(xpaths)
class FormulaEquationInputTemplateTest(TemplateTestCase):
"""
......@@ -481,16 +553,17 @@ class FormulaEquationInputTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'formulaequationinput.html'
def setUp(self):
super(FormulaEquationInputTemplateTest, self).setUp()
self.context = {
'id': 2,
'value': 'PREFILLED_VALUE',
'status': Status('unsubmitted'),
'label': 'test',
'previewer': 'file.js',
'reported_status': 'REPORTED_STATUS',
'trailing_text': None,
'response_data': self.RESPONSE_DATA,
'describedby': self.DESCRIBEDBY,
}
super(FormulaEquationInputTemplateTest, self).setUp()
def test_no_size(self):
xml = self.render_to_xml(self.context)
......@@ -502,6 +575,14 @@ class FormulaEquationInputTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, "//input[@size='40']", self.context)
def test_description(self):
"""
Test that correct description information is set on desired elements.
"""
xpaths = ['//input/@aria-describedby']
self.assert_description(xpaths, descriptions=False)
self.assert_describedby_attribute(xpaths)
class AnnotationInputTemplateTest(TemplateTestCase):
"""
......@@ -511,21 +592,23 @@ class AnnotationInputTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'annotationinput.html'
def setUp(self):
self.context = {'id': 2,
'value': '<p>Test value</p>',
'title': '<h1>This is a title</h1>',
'text': '<p><b>This</b> is a test.</p>',
'comment': '<p>This is a test comment</p>',
'comment_prompt': '<p>This is a test comment prompt</p>',
'comment_value': '<p>This is the value of a test comment</p>',
'tag_prompt': '<p>This is a tag prompt</p>',
'options': [],
'has_options_value': False,
'debug': False,
'status': Status('unsubmitted'),
'return_to_annotation': False,
'msg': '<p>This is a test message</p>', }
super(AnnotationInputTemplateTest, self).setUp()
self.context = {
'id': 2,
'value': '<p>Test value</p>',
'title': '<h1>This is a title</h1>',
'text': '<p><b>This</b> is a test.</p>',
'comment': '<p>This is a test comment</p>',
'comment_prompt': '<p>This is a test comment prompt</p>',
'comment_value': '<p>This is the value of a test comment</p>',
'tag_prompt': '<p>This is a tag prompt</p>',
'options': [],
'has_options_value': False,
'debug': False,
'status': Status('unsubmitted'),
'return_to_annotation': False,
'msg': '<p>This is a test message</p>',
}
def test_return_to_annotation(self):
"""
......@@ -637,8 +720,8 @@ class MathStringTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'mathstring.html'
def setUp(self):
self.context = {'isinline': False, 'mathstr': '', 'tail': ''}
super(MathStringTemplateTest, self).setUp()
self.context = {'isinline': False, 'mathstr': '', 'tail': ''}
def test_math_string_inline(self):
self.context['isinline'] = True
......@@ -679,14 +762,15 @@ class OptionInputTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'optioninput.html'
def setUp(self):
super(OptionInputTemplateTest, self).setUp()
self.context = {
'id': 2,
'options': [],
'status': Status('unsubmitted'),
'label': 'test',
'value': 0
'value': 0,
'response_data': self.RESPONSE_DATA,
'describedby': self.DESCRIBEDBY,
}
super(OptionInputTemplateTest, self).setUp()
def test_select_options(self):
......@@ -730,9 +814,17 @@ class OptionInputTemplateTest(TemplateTestCase):
def test_label(self):
xml = self.render_to_xml(self.context)
xpath = "//select[@aria-label='%s']" % self.context['label']
xpath = "//select[@aria-label='%s']" % self.context['response_data']['label']
self.assert_has_xpath(xml, xpath, self.context)
def test_description(self):
"""
Test that correct description information is set on desired elements.
"""
xpaths = ['//select/@aria-describedby']
self.assert_description(xpaths, descriptions=False)
self.assert_describedby_attribute(xpaths)
class DragAndDropTemplateTest(TemplateTestCase):
"""
......@@ -742,12 +834,12 @@ class DragAndDropTemplateTest(TemplateTestCase):
TEMPLATE_NAME = 'drag_and_drop_input.html'
def setUp(self):
super(DragAndDropTemplateTest, self).setUp()
self.context = {'id': 2,
'drag_and_drop_json': '',
'value': 0,
'status': Status('unsubmitted'),
'msg': ''}
super(DragAndDropTemplateTest, self).setUp()
def test_status(self):
......@@ -799,6 +891,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
'1_choiceinput_1_textinput_0': '0'}
def setUp(self):
super(ChoiceTextGroupTemplateTest, self).setUp()
choices = [
(
'1_choiceinput_0bc',
......@@ -820,12 +913,10 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
'choices': choices,
'status': Status('correct'),
'input_type': 'radio',
'label': 'choicetext label',
'value': self.VALUE_DICT,
'response_data': self.RESPONSE_DATA
}
super(ChoiceTextGroupTemplateTest, self).setUp()
def test_grouping_tag(self):
"""
Tests whether we are using a section or a label to wrap choice elements.
......@@ -965,5 +1056,5 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
def test_label(self):
xml = self.render_to_xml(self.context)
xpath = "//fieldset[@aria-label='%s']" % self.context['label']
xpath = "//fieldset[@aria-label='%s']" % self.context['response_data']['label']
self.assert_has_xpath(xml, xpath, self.context)
......@@ -16,7 +16,7 @@ TODO:
- test funny xml chars -- should never get xml parse error if things are escaped properly.
"""
from collections import OrderedDict
import json
from lxml import etree
from lxml.html import fromstring
......@@ -36,6 +36,14 @@ from capa.xqueue_interface import XQUEUE_TIMEOUT
lookup_tag = inputtypes.registry.get_class_for_tag
DESCRIBEDBY = 'aria-describedby="desc-1 desc-2"'
DESCRIPTIONS = OrderedDict([('desc-1', 'description text 1'), ('desc-2', 'description text 2')])
RESPONSE_DATA = {
'label': 'question text 101',
'descriptions': DESCRIPTIONS
}
def quote_attr(s):
return saxutils.quoteattr(s)[1:-1] # don't want the outer quotes
......@@ -49,9 +57,12 @@ class OptionInputTest(unittest.TestCase):
xml_str = """<optioninput options="('Up','Down','Don't know')" id="sky_input" correct="Up"/>"""
element = etree.fromstring(xml_str)
state = {'value': 'Down',
'id': 'sky_input',
'status': 'answered'}
state = {
'value': 'Down',
'id': 'sky_input',
'status': 'answered',
'response_data': RESPONSE_DATA
}
option_input = lookup_tag('optioninput')(test_capa_system(), element, state)
context = option_input._get_render_context() # pylint: disable=protected-access
......@@ -61,10 +72,11 @@ class OptionInputTest(unittest.TestCase):
'value': 'Down',
'options': [('Up', 'Up'), ('Down', 'Down'), ('Don\'t know', 'Don\'t know')],
'status': inputtypes.Status('answered'),
'label': '',
'msg': '',
'inline': False,
'id': 'sky_input',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -105,12 +117,14 @@ class ChoiceGroupTest(unittest.TestCase):
<choice correct="false" name="foil4">This is <b>foil</b> Four.</choice>
</{tag}>
""".format(tag=tag)
element = etree.fromstring(xml_str)
state = {'value': 'foil3',
'id': 'sky_input',
'status': 'answered'}
state = {
'value': 'foil3',
'id': 'sky_input',
'status': 'answered',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag(tag)(test_capa_system(), element, state)
......@@ -121,7 +135,6 @@ class ChoiceGroupTest(unittest.TestCase):
'id': 'sky_input',
'value': 'foil3',
'status': inputtypes.Status('answered'),
'label': '',
'msg': '',
'input_type': expected_input_type,
'choices': [('foil1', '<text>This is foil One.</text>'),
......@@ -131,6 +144,8 @@ class ChoiceGroupTest(unittest.TestCase):
'show_correctness': 'always',
'submitted_message': 'Answer received.',
'name_array_suffix': expected_suffix, # what is this for??
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -165,7 +180,10 @@ class JavascriptInputTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': '3', }
state = {
'value': '3',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('javascriptinput')(test_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
......@@ -174,13 +192,14 @@ class JavascriptInputTest(unittest.TestCase):
'STATIC_URL': '/dummy-static/',
'id': 'prob_1_2',
'status': inputtypes.Status('unanswered'),
# 'label': '',
'msg': '',
'value': '3',
'params': params,
'display_file': display_file,
'display_class': display_class,
'problem_state': problem_state,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -193,11 +212,14 @@ class TextLineTest(unittest.TestCase):
def test_rendering(self):
size = "42"
xml_str = """<textline id="prob_1_2" label="testing 123" size="{size}"/>""".format(size=size)
xml_str = """<textline id="prob_1_2" size="{size}"/>""".format(size=size)
element = etree.fromstring(xml_str)
state = {'value': 'BumbleBee', }
state = {
'value': 'BumbleBee',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('textline')(test_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
......@@ -207,7 +229,6 @@ class TextLineTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'BumbleBee',
'status': inputtypes.Status('unanswered'),
'label': 'testing 123',
'size': size,
'msg': '',
'hidden': False,
......@@ -215,6 +236,8 @@ class TextLineTest(unittest.TestCase):
'do_math': False,
'trailing_text': '',
'preprocessor': None,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -229,7 +252,10 @@ class TextLineTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': 'BumbleBee', }
state = {
'value': 'BumbleBee',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('textline')(test_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
......@@ -239,7 +265,6 @@ class TextLineTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'BumbleBee',
'status': inputtypes.Status('unanswered'),
'label': '',
'size': size,
'msg': '',
'hidden': False,
......@@ -250,6 +275,8 @@ class TextLineTest(unittest.TestCase):
'class_name': preprocessorClass,
'script_src': script,
},
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -273,7 +300,10 @@ class TextLineTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': 'BumbleBee', }
state = {
'value': 'BumbleBee',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('textline')(test_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
......@@ -283,7 +313,6 @@ class TextLineTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'BumbleBee',
'status': inputtypes.Status('unanswered'),
'label': '',
'size': size,
'msg': '',
'hidden': False,
......@@ -291,6 +320,8 @@ class TextLineTest(unittest.TestCase):
'do_math': False,
'trailing_text': expected_text,
'preprocessor': None,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -312,9 +343,12 @@ class FileSubmissionTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': 'BumbleBee.py',
'status': 'incomplete',
'feedback': {'message': '3'}, }
state = {
'value': 'BumbleBee.py',
'status': 'incomplete',
'feedback': {'message': '3'},
'response_data': RESPONSE_DATA
}
input_class = lookup_tag('filesubmission')
the_input = input_class(test_capa_system(), element, state)
......@@ -324,12 +358,13 @@ class FileSubmissionTest(unittest.TestCase):
'STATIC_URL': '/dummy-static/',
'id': 'prob_1_2',
'status': inputtypes.Status('queued'),
'label': '',
'msg': the_input.submitted_msg,
'value': 'BumbleBee.py',
'queue_len': '3',
'allowed_files': '["runme.py", "nooooo.rb", "ohai.java"]',
'required_files': '["cookies.py"]',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -359,9 +394,12 @@ class CodeInputTest(unittest.TestCase):
escapedict = {'"': '&quot;'}
state = {'value': 'print "good evening"',
'status': 'incomplete',
'feedback': {'message': '3'}, }
state = {
'value': 'print "good evening"',
'status': 'incomplete',
'feedback': {'message': '3'},
'response_data': RESPONSE_DATA
}
input_class = lookup_tag('codeinput')
the_input = input_class(test_capa_system(), element, state)
......@@ -373,7 +411,6 @@ class CodeInputTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
# 'label': '',
'msg': the_input.submitted_msg,
'mode': mode,
'linenumbers': linenumbers,
......@@ -382,6 +419,8 @@ class CodeInputTest(unittest.TestCase):
'hidden': '',
'tabsize': int(tabsize),
'queue_len': '3',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -413,9 +452,12 @@ class MatlabTest(unittest.TestCase):
payload=self.payload,
ln=self.linenumbers)
elt = etree.fromstring(self.xml)
state = {'value': 'print "good evening"',
'status': 'incomplete',
'feedback': {'message': '3'}, }
state = {
'value': 'print "good evening"',
'status': 'incomplete',
'feedback': {'message': '3'},
'response_data': {}
}
self.input_class = lookup_tag('matlabinput')
self.the_input = self.input_class(test_capa_system(), elt, state)
......@@ -428,7 +470,6 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
# 'label': '',
'msg': self.the_input.submitted_msg,
'mode': self.mode,
'rows': self.rows,
......@@ -440,15 +481,20 @@ class MatlabTest(unittest.TestCase):
'button_enabled': True,
'queue_len': '3',
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/octave.js',
'response_data': {},
'describedby': ''
}
self.assertEqual(context, expected)
def test_rendering_with_state(self):
state = {'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queue_msg': 'message'},
'feedback': {'message': '3'}, }
state = {
'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queue_msg': 'message'},
'feedback': {'message': '3'},
'response_data': RESPONSE_DATA
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
......@@ -459,7 +505,6 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
# 'label': '',
'msg': the_input.submitted_msg,
'mode': self.mode,
'rows': self.rows,
......@@ -471,16 +516,20 @@ class MatlabTest(unittest.TestCase):
'button_enabled': True,
'queue_len': '3',
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/octave.js',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
def test_rendering_when_completed(self):
for status in ['correct', 'incorrect']:
state = {'value': 'print "good evening"',
'status': status,
'input_state': {},
}
state = {
'value': 'print "good evening"',
'status': status,
'input_state': {},
'response_data': RESPONSE_DATA
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
......@@ -490,7 +539,6 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status(status),
# 'label': '',
'msg': '',
'mode': self.mode,
'rows': self.rows,
......@@ -502,16 +550,20 @@ class MatlabTest(unittest.TestCase):
'button_enabled': False,
'queue_len': '0',
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/octave.js',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
@patch('capa.inputtypes.time.time', return_value=10)
def test_rendering_while_queued(self, time):
state = {'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queuestate': 'queued', 'queuetime': 5},
}
state = {
'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queuestate': 'queued', 'queuetime': 5},
'response_data': RESPONSE_DATA
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
......@@ -521,7 +573,6 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
# 'label': '',
'msg': the_input.submitted_msg,
'mode': self.mode,
'rows': self.rows,
......@@ -533,6 +584,8 @@ class MatlabTest(unittest.TestCase):
'button_enabled': True,
'queue_len': '1',
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/octave.js',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -650,13 +703,13 @@ class MatlabTest(unittest.TestCase):
textwrap.dedent("""
<div>{\'status\': Status(\'queued\'), \'button_enabled\': True,
\'rows\': \'10\', \'queue_len\': \'3\', \'mode\': \'\',
\'cols\': \'80\', \'STATIC_URL\': \'/dummy-static/\',
\'linenumbers\': \'true\', \'queue_msg\': \'\',
\'tabsize\': 4, \'cols\': \'80\', \'STATIC_URL\': \'/dummy-static/\',
\'describedby\': \'\', \'queue_msg\': \'\',
\'value\': \'print "good evening"\',
\'msg\': u\'Submitted. As soon as a response is returned,
this message will be replaced by that feedback.\',
\'matlab_editor_js\': \'/dummy-static/js/vendor/CodeMirror/octave.js\',
\'hidden\': \'\', \'id\': \'prob_1_2\', \'tabsize\': 4}</div>
\'hidden\': \'\', \'linenumbers\': \'true\', \'id\': \'prob_1_2\', \'response_data\': {}}</div>
""").replace('\n', ' ').strip()
)
......@@ -724,10 +777,13 @@ class MatlabTest(unittest.TestCase):
</div><ul></ul></div>
""")
state = {'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queue_msg': queue_msg},
'feedback': {'message': '3'}, }
state = {
'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queue_msg': queue_msg},
'feedback': {'message': '3'},
'response_data': RESPONSE_DATA
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
......@@ -759,6 +815,8 @@ class MatlabTest(unittest.TestCase):
'button_enabled': True,
'queue_len': '3',
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/octave.js',
'response_data': {},
'describedby': ''
}
self.assertEqual(context, expected)
......@@ -845,8 +903,11 @@ class SchematicTest(unittest.TestCase):
element = etree.fromstring(xml_str)
value = 'three resistors and an oscilating pendulum'
state = {'value': value,
'status': 'unsubmitted'}
state = {
'value': value,
'status': 'unsubmitted',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('schematic')(test_capa_system(), element, state)
......@@ -857,7 +918,6 @@ class SchematicTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'label': '',
'msg': '',
'initial_value': initial_value,
'width': width,
......@@ -866,6 +926,8 @@ class SchematicTest(unittest.TestCase):
'setup_script': '/dummy-static/js/capa/schematicinput.js',
'analyses': analyses,
'submit_analyses': submit_analyses,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -889,8 +951,11 @@ class ImageInputTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': value,
'status': 'unsubmitted'}
state = {
'value': value,
'status': 'unsubmitted',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('imageinput')(test_capa_system(), element, state)
......@@ -901,13 +966,14 @@ class ImageInputTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'label': '',
'width': width,
'height': height,
'src': src,
'gx': egx,
'gy': egy,
'msg': '',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -944,8 +1010,11 @@ class CrystallographyTest(unittest.TestCase):
element = etree.fromstring(xml_str)
value = 'abc'
state = {'value': value,
'status': 'unsubmitted'}
state = {
'value': value,
'status': 'unsubmitted',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('crystallography')(test_capa_system(), element, state)
......@@ -956,10 +1025,11 @@ class CrystallographyTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
# 'label': '',
'msg': '',
'width': width,
'height': height,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -986,8 +1056,11 @@ class VseprTest(unittest.TestCase):
element = etree.fromstring(xml_str)
value = 'abc'
state = {'value': value,
'status': 'unsubmitted'}
state = {
'value': value,
'status': 'unsubmitted',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('vsepr_input')(test_capa_system(), element, state)
......@@ -1003,6 +1076,8 @@ class VseprTest(unittest.TestCase):
'height': height,
'molecules': molecules,
'geometries': geometries,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -1019,7 +1094,10 @@ class ChemicalEquationTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': 'H2OYeah', }
state = {
'value': 'H2OYeah',
'response_data': RESPONSE_DATA
}
self.the_input = lookup_tag('chemicalequationinput')(test_capa_system(), element, state)
def test_rendering(self):
......@@ -1031,10 +1109,11 @@ class ChemicalEquationTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'H2OYeah',
'status': inputtypes.Status('unanswered'),
'label': '',
'msg': '',
'size': self.size,
'previewer': '/dummy-static/js/capa/chemical_equation_preview.js',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -1106,7 +1185,10 @@ class FormulaEquationTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': 'x^2+1/2'}
state = {
'value': 'x^2+1/2',
'response_data': RESPONSE_DATA
}
self.the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state)
def test_rendering(self):
......@@ -1120,12 +1202,13 @@ class FormulaEquationTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'x^2+1/2',
'status': inputtypes.Status('unanswered'),
'label': '',
'msg': '',
'size': self.size,
'previewer': '/dummy-static/js/capa/src/formula_equation_preview.js',
'inline': False,
'trailing_text': '',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -1152,7 +1235,10 @@ class FormulaEquationTest(unittest.TestCase):
element = etree.fromstring(xml_str)
state = {'value': 'x^2+1/2', }
state = {
'value': 'x^2+1/2',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
......@@ -1162,12 +1248,13 @@ class FormulaEquationTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'x^2+1/2',
'status': inputtypes.Status('unanswered'),
'label': '',
'msg': '',
'size': size,
'previewer': '/dummy-static/js/capa/src/formula_equation_preview.js',
'inline': False,
'trailing_text': expected_text,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.assertEqual(context, expected)
......@@ -1263,8 +1350,11 @@ class DragAndDropTest(unittest.TestCase):
element = etree.fromstring(xml_str)
value = 'abc'
state = {'value': value,
'status': 'unsubmitted'}
state = {
'value': value,
'status': 'unsubmitted',
'response_data': RESPONSE_DATA
}
user_input = { # order matters, for string comparison
"target_outline": "false",
......@@ -1293,9 +1383,10 @@ class DragAndDropTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
# 'label': '',
'msg': '',
'drag_and_drop_json': json.dumps(user_input)
'drag_and_drop_json': json.dumps(user_input),
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
# as we are dumping 'draggables' dicts while dumping user_input, string
......@@ -1332,7 +1423,8 @@ class AnnotationInputTest(unittest.TestCase):
state = {
'value': json_value,
'id': 'annotation_input',
'status': 'answered'
'status': 'answered',
'response_data': RESPONSE_DATA
}
tag = 'annotationinput'
......@@ -1345,7 +1437,6 @@ class AnnotationInputTest(unittest.TestCase):
'STATIC_URL': '/dummy-static/',
'id': 'annotation_input',
'status': inputtypes.Status('answered'),
# 'label': '',
'msg': '',
'title': 'foo',
'text': 'bar',
......@@ -1362,7 +1453,9 @@ class AnnotationInputTest(unittest.TestCase):
'has_options_value': len(value['options']) > 0,
'comment_value': value['comment'],
'debug': False,
'return_to_annotation': True
'return_to_annotation': True,
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
self.maxDiff = None
......@@ -1405,6 +1498,7 @@ class TestChoiceText(unittest.TestCase):
'value': '{}',
'id': 'choicetext_input',
'status': inputtypes.Status('answered'),
'response_data': RESPONSE_DATA
}
first_input = self.build_choice_element('numtolerance_input', 'choiceinput_0_textinput_0', 'false', '')
......@@ -1421,11 +1515,12 @@ class TestChoiceText(unittest.TestCase):
expected = {
'STATIC_URL': '/dummy-static/',
'msg': '',
'label': '',
'input_type': expected_input_type,
'choices': choices,
'show_correctness': 'always',
'submitted_message': 'Answer received.'
'submitted_message': 'Answer received.',
'response_data': RESPONSE_DATA,
'describedby': DESCRIBEDBY
}
expected.update(state)
the_input = lookup_tag(tag)(test_capa_system(), element, state)
......
......@@ -1256,7 +1256,6 @@ class CapaMixin(CapaFields):
of the problem. If problem related metadata cannot be located it should be replaced with empty
strings ''.
"""
input_metadata = {}
for input_id, internal_answer in answers.iteritems():
answer_input = self.lcp.inputs.get(input_id)
......@@ -1290,7 +1289,7 @@ class CapaMixin(CapaFields):
is_correct = ''
input_metadata[input_id] = {
'question': getattr(answer_input, 'loaded_attributes', {}).get('label', ''),
'question': answer_input.response_data.get('label', ''),
'answer': user_visible_answer,
'response_type': getattr(getattr(answer_response, 'xml', None), 'tag', ''),
'input_type': getattr(answer_input, 'tag', ''),
......
......@@ -153,11 +153,8 @@ div.problem {
}
}
span > label {
display: block;
margin-bottom: $baseline;
font: inherit;
color: inherit;
.question-description {
@include margin(($baseline*0.75), 0);
}
}
......
......@@ -235,7 +235,7 @@ describe 'MarkdownEditingDescriptor', ->
<p>A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets.</p>
<p>One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make.</p>
<label>What Apple device competed with the portable CD player?</label>
<choicegroup label="What Apple device competed with the portable CD player?" type="MultipleChoice">
<choicegroup type="MultipleChoice">
<choice correct="false">The iPad</choice>
<choice correct="false">Napster</choice>
<choice correct="true">The iPod</choice>
......@@ -488,7 +488,7 @@ describe 'MarkdownEditingDescriptor', ->
<problem>
<stringresponse answer="w*.?s*Luther Kings*.*" type="ci regexp">
<label>Who lead the civil right movement in the United States of America?</label>
<textline label="Who lead the civil right movement in the United States of America?" size="20"/>
<textline size="20"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......@@ -512,28 +512,27 @@ describe 'MarkdownEditingDescriptor', ->
(x) Berlin
( ) Donut
""")
expect(data).toXMLEqual("""<problem>
<p>France is a country in Europe.</p>
<p>What is the capital of France?</p>
<stringresponse answer="Paris" type="ci" >
<textline label="What is the capital of France?" size="20"/>
</stringresponse>
<p>Germany is a country in Europe, too.</p>
expect(data).toXMLEqual("""
<problem>
<p>France is a country in Europe.</p>
<p>What is the capital of Germany?</p>
<multiplechoiceresponse>
<choicegroup label="What is the capital of Germany?" type="MultipleChoice">
<choice correct="false">Bonn</choice>
<choice correct="false">Hamburg</choice>
<choice correct="true">Berlin</choice>
<choice correct="false">Donut</choice>
</choicegroup>
</multiplechoiceresponse>
<label>What is the capital of France?</label>
<stringresponse answer="Paris" type="ci" >
<textline size="20"/>
</stringresponse>
<p>Germany is a country in Europe, too.</p>
</problem>""")
<label>What is the capital of Germany?</label>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Bonn</choice>
<choice correct="false">Hamburg</choice>
<choice correct="true">Berlin</choice>
<choice correct="false">Donut</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>""")
it 'tests multiple questions with only one label', ->
data = MarkdownEditingDescriptor.markdownToXml("""
France is a country in Europe.
......@@ -549,28 +548,27 @@ describe 'MarkdownEditingDescriptor', ->
(x) Berlin
( ) Donut
""")
expect(data).toXMLEqual("""<problem>
<p>France is a country in Europe.</p>
<p>What is the capital of France?</p>
<stringresponse answer="Paris" type="ci" >
<textline label="What is the capital of France?" size="20"/>
</stringresponse>
<p>Germany is a country in Europe, too.</p>
expect(data).toXMLEqual("""
<problem>
<p>France is a country in Europe.</p>
<p>What is the capital of Germany?</p>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Bonn</choice>
<choice correct="false">Hamburg</choice>
<choice correct="true">Berlin</choice>
<choice correct="false">Donut</choice>
</choicegroup>
</multiplechoiceresponse>
<label>What is the capital of France?</label>
<stringresponse answer="Paris" type="ci" >
<textline size="20"/>
</stringresponse>
<p>Germany is a country in Europe, too.</p>
</problem>""")
<p>What is the capital of Germany?</p>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Bonn</choice>
<choice correct="false">Hamburg</choice>
<choice correct="true">Berlin</choice>
<choice correct="false">Donut</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>""")
it 'adds labels to formulae', ->
data = MarkdownEditingDescriptor.markdownToXml("""
......@@ -581,7 +579,7 @@ describe 'MarkdownEditingDescriptor', ->
<numericalresponse answer="3.14159">
<label>Enter the numerical value of Pi:</label>
<responseparam type="tolerance" default=".02"/>
<formulaequationinput label="Enter the numerical value of Pi:"/>
<formulaequationinput/>
</numericalresponse>
......@@ -752,7 +750,7 @@ describe 'MarkdownEditingDescriptor', ->
<multiplechoiceresponse>
<p>Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text.</p>
<label>Which of the following countries has the largest population?</label>
<choicegroup label="Which of the following countries has the largest population?" type="MultipleChoice">
<choicegroup type="MultipleChoice">
<choice correct="false">Brazil <choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint>
</choice>
<choice correct="false">Germany</choice>
......@@ -774,7 +772,7 @@ describe 'MarkdownEditingDescriptor', ->
<choiceresponse>
<p>Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text.</p>
<label>The following languages are in the Indo-European family:</label>
<checkboxgroup label="The following languages are in the Indo-European family:">
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
......@@ -818,7 +816,7 @@ describe 'MarkdownEditingDescriptor', ->
<multiplechoiceresponse>
<label>Which of the following countries has the largest population?</label>
<choicegroup label="Which of the following countries has the largest population?" type="MultipleChoice">
<choicegroup type="MultipleChoice">
<choice correct="false">Brazil <choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint>
</choice>
<choice correct="false">Germany</choice>
......@@ -839,9 +837,9 @@ describe 'MarkdownEditingDescriptor', ->
</problem>
""")
it 'can do separation if spaces are prsent around ---', ->
it 'can do separation if spaces are present around ---', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>The following languages are in the Indo-European family:<<
>>The following languages are in the Indo-European family:||There are three correct choices.<<
[x] Urdu
[ ] Finnish
[x] Marathi
......@@ -850,7 +848,7 @@ describe 'MarkdownEditingDescriptor', ->
---
>>Which of the following countries has the largest population?<<
>>Which of the following countries has the largest population?||You have only choice.<<
( ) Brazil {{ timely feedback -- explain why an almost correct answer is wrong }}
( ) Germany
(x) Indonesia
......@@ -858,30 +856,99 @@ describe 'MarkdownEditingDescriptor', ->
""")
expect(data).toXMLEqual("""
<problem>
<choiceresponse>
<label>The following languages are in the Indo-European family:</label>
<checkboxgroup label="The following languages are in the Indo-European family:">
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
<choice correct="true">French</choice>
<choice correct="false">Hungarian</choice>
</checkboxgroup>
</choiceresponse>
<choiceresponse>
<label>The following languages are in the Indo-European family:</label>
<description>There are three correct choices.</description>
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
<choice correct="true">French</choice>
<choice correct="false">Hungarian</choice>
</checkboxgroup>
</choiceresponse>
<multiplechoiceresponse>
<label>Which of the following countries has the largest population?</label>
<description>You have only choice.</description>
<choicegroup type="MultipleChoice">
<choice correct="false">Brazil
<choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint>
</choice>
<choice correct="false">Germany</choice>
<choice correct="true">Indonesia</choice>
<choice correct="false">Russia</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>
""")
<multiplechoiceresponse>
<label>Which of the following countries has the largest population?</label>
<choicegroup label="Which of the following countries has the largest population?" type="MultipleChoice">
<choice correct="false">Brazil <choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint>
</choice>
<choice correct="false">Germany</choice>
<choice correct="true">Indonesia</choice>
<choice correct="false">Russia</choice>
</choicegroup>
</multiplechoiceresponse>
it 'can extract question description', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>The following languages are in the Indo-European family:||Choose wisely.<<
[x] Urdu
[ ] Finnish
[x] Marathi
[x] French
[ ] Hungarian
""")
expect(data).toXMLEqual("""
<problem>
<choiceresponse>
<label>The following languages are in the Indo-European family:</label>
<description>Choose wisely.</description>
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
<choice correct="true">French</choice>
<choice correct="false">Hungarian</choice>
</checkboxgroup>
</choiceresponse>
</problem>
""")
it 'can handle question and description spanned across multiple lines', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>The following languages
are in the
Indo-European family:
||
first second
third
<<
[x] Urdu
[ ] Finnish
[x] Marathi
""")
expect(data).toXMLEqual("""
<problem>
<choiceresponse>
<label>The following languages are in the Indo-European family:</label>
<description>first second third</description>
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
</checkboxgroup>
</choiceresponse>
</problem>
""")
it 'will not add empty description', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>The following languages are in the Indo-European family:||<<
[x] Urdu
[ ] Finnish
""")
expect(data).toXMLEqual("""
<problem>
<choiceresponse>
<label>The following languages are in the Indo-European family:</label>
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
</checkboxgroup>
</choiceresponse>
</problem>
""")
......@@ -119,7 +119,7 @@ describe 'Markdown to xml extended hint dropdown', ->
<problem>
<optionresponse>
<label>q1</label>
<optioninput label="q1">
<optioninput>
<option correct="True">aa <optionhint>hint1</optionhint>
</option>
<option correct="False">bb</option>
......@@ -149,7 +149,7 @@ describe 'Markdown to xml extended hint dropdown', ->
<problem>
<optionresponse>
<label>q1</label>
<optioninput label="q1">
<optioninput>
<option correct="False">aa <optionhint>hint1</optionhint>
</option>
<option correct="False">bb <optionhint>hint2</optionhint>
......@@ -191,77 +191,76 @@ describe 'Markdown to xml extended hint checkbox', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>Select all the fruits from the list</p>
<choiceresponse>
<checkboxgroup label="Select all the fruits from the list">
<choice correct="true">Apple
<choicehint selected="true">You're right that apple is a fruit.</choicehint>
<choicehint selected="false">Remember that apple is also a fruit.</choicehint></choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a fruit.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't fruit</choicehint></choice>
<choice correct="true">Grape
<choicehint selected="true">You're right that grape is a fruit</choicehint>
<choicehint selected="false">Remember that grape is also a fruit.</choicehint></choice>
<choice correct="false">Mustang</choice>
<choice correct="false">Camero
<choicehint selected="true">I don't know what a Camero is but it isn't a fruit.</choicehint>
<choicehint selected="false">What is a camero anyway?</choicehint></choice>
<compoundhint value="A*B">You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
<compoundhint value="B*C">You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
</checkboxgroup>
</choiceresponse>
<p>Select all the vegetables from the list</p>
<choiceresponse>
<checkboxgroup label="Select all the vegetables from the list">
<choice correct="false">Banana
<choicehint selected="true">No, sorry, a banana is a fruit.</choicehint>
<choicehint selected="false">poor banana.</choicehint></choice>
<choice correct="false">Ice Cream</choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a vegetable.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't vegetables.</choicehint></choice>
<choice correct="true">Brussel Sprout
<choicehint selected="true">Brussel sprouts are vegetables.</choicehint>
<choicehint selected="false">Brussel sprout is the only vegetable in this list.</choicehint></choice>
<compoundhint value="A*B">Making a banana split?</compoundhint>
<compoundhint value="B*D">That will make a horrible dessert: a brussel sprout split?</compoundhint>
</checkboxgroup>
</choiceresponse>
<label>Select all the fruits from the list</label>
<choiceresponse>
<checkboxgroup>
<choice correct="true">Apple
<choicehint selected="true">You're right that apple is a fruit.</choicehint>
<choicehint selected="false">Remember that apple is also a fruit.</choicehint>
</choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a fruit.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't fruit</choicehint>
</choice>
<choice correct="true">Grape
<choicehint selected="true">You're right that grape is a fruit</choicehint>
<choicehint selected="false">Remember that grape is also a fruit.</choicehint>
</choice>
<choice correct="false">Mustang</choice>
<choice correct="false">Camero
<choicehint selected="true">I don't know what a Camero is but it isn't a fruit.</choicehint>
<choicehint selected="false">What is a camero anyway?</choicehint>
</choice>
<compoundhint value="A*B">You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
<compoundhint value="B*C">You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
</checkboxgroup>
</choiceresponse>
<label>Select all the vegetables from the list</label>
<choiceresponse>
<checkboxgroup>
<choice correct="false">Banana
<choicehint selected="true">No, sorry, a banana is a fruit.</choicehint>
<choicehint selected="false">poor banana.</choicehint>
</choice>
<choice correct="false">Ice Cream</choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a vegetable.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't vegetables.</choicehint>
</choice>
<choice correct="true">Brussel Sprout
<choicehint selected="true">Brussel sprouts are vegetables.</choicehint>
<choicehint selected="false">Brussel sprout is the only vegetable in this list.</choicehint>
</choice>
<compoundhint value="A*B">Making a banana split?</compoundhint>
<compoundhint value="B*D">That will make a horrible dessert: a brussel sprout split?</compoundhint>
</checkboxgroup>
</choiceresponse>
</problem>
""")
it 'produces xml also with demand hints', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>Select all the fruits from the list<<
[x] Apple {{ selected: You're right that apple is a fruit. }, {unselected: Remember that apple is also a fruit.}}
[ ] Mushroom {{U: You're right that mushrooms aren't fruit}, { selected: Mushroom is a fungus, not a fruit.}}
[x] Grape {{ selected: You're right that grape is a fruit }, {unselected: Remember that grape is also a fruit.}}
[ ] Mustang
[ ] Camero {{S:I don't know what a Camero is but it isn't a fruit.},{U:What is a camero anyway?}}
{{ ((A*B)) You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.}}
{{ ((B*C)) You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit.}}
[x] Apple {{ selected: You're right that apple is a fruit. }, {unselected: Remember that apple is also a fruit.}}
[ ] Mushroom {{U: You're right that mushrooms aren't fruit}, { selected: Mushroom is a fungus, not a fruit.}}
[x] Grape {{ selected: You're right that grape is a fruit }, {unselected: Remember that grape is also a fruit.}}
[ ] Mustang
[ ] Camero {{S:I don't know what a Camero is but it isn't a fruit.},{U:What is a camero anyway?}}
{{ ((A*B)) You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.}}
{{ ((B*C)) You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit.}}
>>Select all the vegetables from the list<<
[ ] Banana {{ selected: No, sorry, a banana is a fruit. }, {unselected: poor banana.}}
[ ] Ice Cream
[ ] Mushroom {{U: You're right that mushrooms aren't vegatbles}, { selected: Mushroom is a fungus, not a vegetable.}}
[x] Brussel Sprout {{S: Brussel sprouts are vegetables.}, {u: Brussel sprout is the only vegetable in this list.}}
{{ ((A*B)) Making a banana split? }}
{{ ((B*D)) That will make a horrible dessert: a brussel sprout split? }}
[ ] Banana {{ selected: No, sorry, a banana is a fruit. }, {unselected: poor banana.}}
[ ] Ice Cream
[ ] Mushroom {{U: You're right that mushrooms aren't vegatbles}, { selected: Mushroom is a fungus, not a vegetable.}}
[x] Brussel Sprout {{S: Brussel sprouts are vegetables.}, {u: Brussel sprout is the only vegetable in this list.}}
{{ ((A*B)) Making a banana split? }}
{{ ((B*D)) That will make a horrible dessert: a brussel sprout split? }}
|| Hint one.||
|| Hint two. ||
......@@ -269,51 +268,57 @@ describe 'Markdown to xml extended hint checkbox', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>Select all the fruits from the list</p>
<choiceresponse>
<checkboxgroup label="Select all the fruits from the list">
<choice correct="true">Apple
<choicehint selected="true">You're right that apple is a fruit.</choicehint>
<choicehint selected="false">Remember that apple is also a fruit.</choicehint></choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a fruit.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't fruit</choicehint></choice>
<choice correct="true">Grape
<choicehint selected="true">You're right that grape is a fruit</choicehint>
<choicehint selected="false">Remember that grape is also a fruit.</choicehint></choice>
<choice correct="false">Mustang</choice>
<choice correct="false">Camero
<choicehint selected="true">I don't know what a Camero is but it isn't a fruit.</choicehint>
<choicehint selected="false">What is a camero anyway?</choicehint></choice>
<compoundhint value="A*B">You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
<compoundhint value="B*C">You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
</checkboxgroup>
</choiceresponse>
<p>Select all the vegetables from the list</p>
<choiceresponse>
<checkboxgroup label="Select all the vegetables from the list">
<choice correct="false">Banana
<choicehint selected="true">No, sorry, a banana is a fruit.</choicehint>
<choicehint selected="false">poor banana.</choicehint></choice>
<choice correct="false">Ice Cream</choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a vegetable.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't vegatbles</choicehint></choice>
<choice correct="true">Brussel Sprout
<choicehint selected="true">Brussel sprouts are vegetables.</choicehint>
<choicehint selected="false">Brussel sprout is the only vegetable in this list.</choicehint></choice>
<compoundhint value="A*B">Making a banana split?</compoundhint>
<compoundhint value="B*D">That will make a horrible dessert: a brussel sprout split?</compoundhint>
</checkboxgroup>
</choiceresponse>
<demandhint>
<hint>Hint one.</hint>
<hint>Hint two.</hint>
<hint>Hint three.</hint>
</demandhint>
<label>Select all the fruits from the list</label>
<choiceresponse>
<checkboxgroup>
<choice correct="true">Apple
<choicehint selected="true">You're right that apple is a fruit.</choicehint>
<choicehint selected="false">Remember that apple is also a fruit.</choicehint>
</choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a fruit.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't fruit</choicehint>
</choice>
<choice correct="true">Grape
<choicehint selected="true">You're right that grape is a fruit</choicehint>
<choicehint selected="false">Remember that grape is also a fruit.</choicehint>
</choice>
<choice correct="false">Mustang</choice>
<choice correct="false">Camero
<choicehint selected="true">I don't know what a Camero is but it isn't a fruit.</choicehint>
<choicehint selected="false">What is a camero anyway?</choicehint>
</choice>
<compoundhint value="A*B">You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
<compoundhint value="B*C">You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit.</compoundhint>
</checkboxgroup>
</choiceresponse>
<label>Select all the vegetables from the list</label>
<choiceresponse>
<checkboxgroup>
<choice correct="false">Banana
<choicehint selected="true">No, sorry, a banana is a fruit.</choicehint>
<choicehint selected="false">poor banana.</choicehint>
</choice>
<choice correct="false">Ice Cream</choice>
<choice correct="false">Mushroom
<choicehint selected="true">Mushroom is a fungus, not a vegetable.</choicehint>
<choicehint selected="false">You're right that mushrooms aren't vegatbles</choicehint>
</choice>
<choice correct="true">Brussel Sprout
<choicehint selected="true">Brussel sprouts are vegetables.</choicehint>
<choicehint selected="false">Brussel sprout is the only vegetable in this list.</choicehint>
</choice>
<compoundhint value="A*B">Making a banana split?</compoundhint>
<compoundhint value="B*D">That will make a horrible dessert: a brussel sprout split?</compoundhint>
</checkboxgroup>
</choiceresponse>
<demandhint>
<hint>Hint one.</hint>
<hint>Hint two.</hint>
<hint>Hint three.</hint>
</demandhint>
</problem>
""")
......@@ -323,92 +328,105 @@ describe 'Markdown to xml extended hint multiple choice', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>Select the fruit from the list<<
() Mushroom {{ Mushroom is a fungus, not a fruit.}}
() Potato
(x) Apple {{ OUTSTANDING::Apple is indeed a fruit.}}
() Mushroom {{ Mushroom is a fungus, not a fruit.}}
() Potato
(x) Apple {{ OUTSTANDING::Apple is indeed a fruit.}}
>>Select the vegetables from the list<<
() Mushroom {{ Mushroom is a fungus, not a vegetable.}}
(x) Potato {{ Potato is a root vegetable. }}
() Apple {{ OOPS::Apple is a fruit.}}
() Mushroom {{ Mushroom is a fungus, not a vegetable.}}
(x) Potato {{ Potato is a root vegetable. }}
() Apple {{ OOPS::Apple is a fruit.}}
""")
expect(data).toXMLEqual("""
<problem>
<p>Select the fruit from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the fruit from the list" type="MultipleChoice">
<choice correct="false">Mushroom <choicehint>Mushroom is a fungus, not a fruit.</choicehint></choice>
<choice correct="false">Potato</choice>
<choice correct="true">Apple <choicehint label="OUTSTANDING">Apple is indeed a fruit.</choicehint></choice>
</choicegroup>
</multiplechoiceresponse>
<p>Select the vegetables from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the vegetables from the list" type="MultipleChoice">
<choice correct="false">Mushroom <choicehint>Mushroom is a fungus, not a vegetable.</choicehint></choice>
<choice correct="true">Potato <choicehint>Potato is a root vegetable.</choicehint></choice>
<choice correct="false">Apple <choicehint label="OOPS">Apple is a fruit.</choicehint></choice>
</choicegroup>
</multiplechoiceresponse>
<label>Select the fruit from the list</label>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint>Mushroom is a fungus, not a fruit.</choicehint>
</choice>
<choice correct="false">Potato</choice>
<choice correct="true">Apple
<choicehint label="OUTSTANDING">Apple is indeed a fruit.</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
<label>Select the vegetables from the list</label>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint>Mushroom is a fungus, not a vegetable.</choicehint>
</choice>
<choice correct="true">Potato
<choicehint>Potato is a root vegetable.</choicehint>
</choice>
<choice correct="false">Apple
<choicehint label="OOPS">Apple is a fruit.</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>
""")
it 'produces xml with demand hints', ->
data = MarkdownEditingDescriptor.markdownToXml("""
>>Select the fruit from the list<<
() Mushroom {{ Mushroom is a fungus, not a fruit.}}
() Potato
(x) Apple {{ OUTSTANDING::Apple is indeed a fruit.}}
|| 0) spaces on previous line. ||
|| 1) roses are red. ||
>>Select the vegetables from the list<<
>>Select the fruit from the list<<
() Mushroom {{ Mushroom is a fungus, not a vegetable.}}
() Mushroom {{ Mushroom is a fungus, not a fruit.}}
() Potato
(x) Apple {{ OUTSTANDING::Apple is indeed a fruit.}}
(x) Potato {{ Potato is a root vegetable. }}
() Apple {{ OOPS::Apple is a fruit.}}
|| 0) spaces on previous line. ||
|| 1) roses are red. ||
>>Select the vegetables from the list<<
|| 2) where are the lions? ||
() Mushroom {{ Mushroom is a fungus, not a vegetable.}}
(x) Potato {{ Potato is a root vegetable. }}
() Apple {{ OOPS::Apple is a fruit.}}
|| 2) where are the lions? ||
""")
expect(data).toXMLEqual("""
<problem>
<p>Select the fruit from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the fruit from the list" type="MultipleChoice">
<choice correct="false">Mushroom <choicehint>Mushroom is a fungus, not a fruit.</choicehint></choice>
<choice correct="false">Potato</choice>
<choice correct="true">Apple <choicehint label="OUTSTANDING">Apple is indeed a fruit.</choicehint></choice>
</choicegroup>
</multiplechoiceresponse>
<p>Select the vegetables from the list</p>
<multiplechoiceresponse>
<choicegroup label="Select the vegetables from the list" type="MultipleChoice">
<choice correct="false">Mushroom <choicehint>Mushroom is a fungus, not a vegetable.</choicehint></choice>
<choice correct="true">Potato <choicehint>Potato is a root vegetable.</choicehint></choice>
<choice correct="false">Apple <choicehint label="OOPS">Apple is a fruit.</choicehint></choice>
</choicegroup>
</multiplechoiceresponse>
<demandhint>
<hint>0) spaces on previous line.</hint>
<hint>1) roses are red.</hint>
<hint>2) where are the lions?</hint>
</demandhint>
</problem>
""")
<problem>
<label>Select the fruit from the list</label>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint>Mushroom is a fungus, not a fruit.</choicehint>
</choice>
<choice correct="false">Potato</choice>
<choice correct="true">Apple
<choicehint label="OUTSTANDING">Apple is indeed a fruit.</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
<label>Select the vegetables from the list</label>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="false">Mushroom
<choicehint>Mushroom is a fungus, not a vegetable.</choicehint>
</choice>
<choice correct="true">Potato
<choicehint>Potato is a root vegetable.</choicehint>
</choice>
<choice correct="false">Apple
<choicehint label="OOPS">Apple is a fruit.</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
<demandhint>
<hint>0) spaces on previous line.</hint>
<hint>1) roses are red.</hint>
<hint>2) where are the lions?</hint>
</demandhint>
</problem>
""")
describe 'Markdown to xml extended hint text input', ->
......@@ -422,7 +440,7 @@ describe 'Markdown to xml extended hint text input', ->
<stringresponse answer="France" type="ci">
<label>In which country would you find the city of Paris?</label>
<correcthint label="BRAVO">Viva la France!</correcthint>
<textline label="In which country would you find the city of Paris?" size="20"/>
<textline size="20"/>
</stringresponse>
......@@ -442,7 +460,7 @@ describe 'Markdown to xml extended hint text input', ->
<correcthint label="BRAVO">hint1</correcthint>
<additional_answer answer="USA"><correcthint label="meh">hint2</correcthint>
</additional_answer>
<textline label="Where Paris?" size="20"/>
<textline size="20"/>
</stringresponse>
......@@ -461,7 +479,7 @@ describe 'Markdown to xml extended hint text input', ->
<label>Revenge is a dish best served</label>
<correcthint>khaaaaaan!</correcthint>
<stringequalhint answer="warm">feedback2</stringequalhint>
<textline label="Revenge is a dish best served" size="20"/>
<textline size="20"/>
</stringresponse>
......@@ -478,7 +496,7 @@ describe 'Markdown to xml extended hint text input', ->
<stringresponse answer="2" type="ci">
<label>q</label>
<correcthint>feedback1</correcthint>
<textline label="q" size="20"/>
<textline size="20"/>
</stringresponse>
......@@ -501,7 +519,7 @@ describe 'Markdown to xml extended hint text input', ->
</additional_answer>
<stringequalhint answer="no">feedback2</stringequalhint>
<additional_answer answer="ccc"/>
<textline label="q" size="20"/>
<textline size="20"/>
</stringresponse>
......@@ -523,7 +541,7 @@ describe 'Markdown to xml extended hint text input', ->
<additional_answer answer="bbb"><correcthint>feedback2</correcthint>
</additional_answer>
<additional_answer answer="ccc"/>
<textline label="q" size="20"/>
<textline size="20"/>
</stringresponse>
......@@ -531,23 +549,22 @@ describe 'Markdown to xml extended hint text input', ->
""")
it 'produces xml with each = making a new question', ->
data = MarkdownEditingDescriptor.markdownToXml(""">>q<<
= aaa
or= bbb
s= ccc
data = MarkdownEditingDescriptor.markdownToXml("""
>>q<<
= aaa
or= bbb
s= ccc
""")
expect(data).toXMLEqual("""
<problem>
<p>q</p>
<stringresponse answer="aaa" type="ci" >
<additional_answer answer="bbb"></additional_answer>
<textline label="q" size="20"/>
</stringresponse>
<stringresponse answer="ccc" type="ci" >
<textline size="20"/>
</stringresponse>
<label>q</label>
<stringresponse answer="aaa" type="ci">
<additional_answer answer="bbb"></additional_answer>
<textline size="20"/>
</stringresponse>
<stringresponse answer="ccc" type="ci">
<textline size="20"/>
</stringresponse>
</problem>
""")
......@@ -565,18 +582,16 @@ describe 'Markdown to xml extended hint text input', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>paragraph</p>
<p>q</p>
<stringresponse answer="aaa" type="ci" >
<additional_answer answer="bbb"></additional_answer>
<textline label="q" size="20"/>
</stringresponse>
<stringresponse answer="ccc" type="ci" >
<textline size="20"/>
</stringresponse>
<p>paragraph 2</p>
<p>paragraph</p>
<label>q</label>
<stringresponse answer="aaa" type="ci">
<additional_answer answer="bbb"></additional_answer>
<textline size="20"/>
</stringresponse>
<stringresponse answer="ccc" type="ci">
<textline size="20"/>
</stringresponse>
<p>paragraph 2</p>
</problem>
""")
......@@ -590,16 +605,16 @@ describe 'Markdown to xml extended hint text input', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>paragraph</p>
<p>q</p>
<p>or= aaa</p>
<p>paragraph 2</p>
<p>paragraph</p>
<label>q</label>
<p>or= aaa</p>
<p>paragraph 2</p>
</problem>
""")
it 'produces xml with each = with feedback making a new question', ->
data = MarkdownEditingDescriptor.markdownToXml(""">>q<<
data = MarkdownEditingDescriptor.markdownToXml("""
>>q<<
s= aaa
or= bbb {{feedback1}}
= ccc {{feedback2}}
......@@ -607,16 +622,17 @@ describe 'Markdown to xml extended hint text input', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>q</p>
<stringresponse answer="aaa" type="ci" >
<additional_answer answer="bbb"><correcthint>feedback1</correcthint></additional_answer>
<textline label="q" size="20"/>
</stringresponse>
<stringresponse answer="ccc" type="ci" >
<correcthint>feedback2</correcthint>
<textline size="20"/>
</stringresponse>
<label>q</label>
<stringresponse answer="aaa" type="ci">
<additional_answer answer="bbb">
<correcthint>feedback1</correcthint>
</additional_answer>
<textline size="20"/>
</stringresponse>
<stringresponse answer="ccc" type="ci">
<correcthint>feedback2</correcthint>
<textline size="20"/>
</stringresponse>
</problem>
""")
......@@ -633,7 +649,7 @@ describe 'Markdown to xml extended hint text input', ->
<stringresponse answer="France" type="ci">
<label>Where Paris?</label>
<correcthint label="BRAVO">hint1</correcthint>
<textline label="Where Paris?" size="20"/>
<textline size="20"/>
</stringresponse>
<demandhint>
......@@ -655,30 +671,27 @@ describe 'Markdown to xml extended hint numeric input', ->
>>Enter the number of fingers on a human hand<<
= 5
""")
expect(data).toXMLEqual("""
<problem>
<p>Enter the numerical value of Pi:</p>
<numericalresponse answer="3.14159">
<responseparam type="tolerance" default=".02" />
<formulaequationinput label="Enter the numerical value of Pi:" />
<correcthint>Pie for everyone!</correcthint>
</numericalresponse>
<p>Enter the approximate value of 502*9:</p>
<numericalresponse answer="4518">
<responseparam type="tolerance" default="15%" />
<formulaequationinput label="Enter the approximate value of 502*9:" />
<correcthint label="PIE">No pie for you!</correcthint>
</numericalresponse>
<p>Enter the number of fingers on a human hand</p>
<numericalresponse answer="5">
<formulaequationinput label="Enter the number of fingers on a human hand" />
</numericalresponse>
<label>Enter the numerical value of Pi:</label>
<numericalresponse answer="3.14159">
<responseparam type="tolerance" default=".02"/>
<formulaequationinput/>
<correcthint>Pie for everyone!</correcthint>
</numericalresponse>
<label>Enter the approximate value of 502*9:</label>
<numericalresponse answer="4518">
<responseparam type="tolerance" default="15%"/>
<formulaequationinput/>
<correcthint label="PIE">No pie for you!</correcthint>
</numericalresponse>
<label>Enter the number of fingers on a human hand</label>
<numericalresponse answer="5">
<formulaequationinput/>
</numericalresponse>
</problem>
""")
......@@ -697,21 +710,21 @@ describe 'Markdown to xml extended hint numeric input', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>text1</p>
<numericalresponse answer="1">
<formulaequationinput label="text1" />
<correcthint>hint1</correcthint>
</numericalresponse>
<p>text2</p>
<numericalresponse answer="2">
<formulaequationinput label="text2" />
<correcthint>hint2</correcthint>
</numericalresponse>
<demandhint>
<hint>hintA</hint>
<hint>hintB</hint>
</demandhint>
<label>text1</label>
<numericalresponse answer="1">
<formulaequationinput/>
<correcthint>hint1</correcthint>
</numericalresponse>
<label>text2</label>
<numericalresponse answer="2">
<formulaequationinput/>
<correcthint>hint2</correcthint>
</numericalresponse>
<demandhint>
<hint>hintA</hint>
<hint>hintB</hint>
</demandhint>
</problem>
""")
......@@ -765,55 +778,68 @@ describe 'Markdown to xml extended hint with multiline hints', ->
""")
expect(data).toXMLEqual("""
<problem>
<p>Checkboxes</p>
<choiceresponse>
<checkboxgroup label="Checkboxes">
<choice correct="true">A
<choicehint selected="true">aaa</choicehint>
<choicehint selected="false">bbb</choicehint></choice>
<choice correct="false">B
<choicehint selected="true">d.</choicehint>
<choicehint selected="false">c</choicehint></choice>
<compoundhint value="A*B">A*B hint</compoundhint>
</checkboxgroup>
</choiceresponse>
<p>What is 1 + 1?</p>
<numericalresponse answer="2">
<formulaequationinput label="What is 1 + 1?" />
<correcthint>part one, and part two</correcthint>
</numericalresponse>
<p>hello?</p>
<stringresponse answer="hello" type="ci" >
<correcthint>hello hint</correcthint>
<textline label="hello?" size="20"/>
</stringresponse>
<p>multiple choice</p>
<multiplechoiceresponse>
<choicegroup label="multiple choice" type="MultipleChoice">
<choice correct="true">AA <choicehint>hint1</choicehint></choice>
<choice correct="false">BB <choicehint>hint2</choicehint></choice>
<choice correct="false">CC <choicehint>hint3</choicehint></choice>
</choicegroup>
</multiplechoiceresponse>
<p>dropdown</p>
<optionresponse>
<optioninput label="dropdown">
<option correct="False">W1 <optionhint>no</optionhint></option>
<option correct="False">W2 <optionhint>nope</optionhint></option>
<option correct="True">C1 <optionhint>yes</optionhint></option>
</optioninput>
</optionresponse>
<demandhint>
<hint>aaa</hint>
<hint>bbb</hint>
<hint>ccc</hint>
</demandhint>
<label>Checkboxes</label>
<choiceresponse>
<checkboxgroup>
<choice correct="true">A
<choicehint selected="true">aaa</choicehint>
<choicehint selected="false">bbb</choicehint>
</choice>
<choice correct="false">B
<choicehint selected="true">d.</choicehint>
<choicehint selected="false">c</choicehint>
</choice>
<compoundhint value="A*B">A*B hint</compoundhint>
</checkboxgroup>
</choiceresponse>
<label>What is 1 + 1?</label>
<numericalresponse answer="2">
<formulaequationinput/>
<correcthint>part one, and part two</correcthint>
</numericalresponse>
<label>hello?</label>
<stringresponse answer="hello" type="ci">
<correcthint>hello hint</correcthint>
<textline size="20"/>
</stringresponse>
<label>multiple choice</label>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
<choice correct="true">AA
<choicehint>hint1</choicehint>
</choice>
<choice correct="false">BB
<choicehint>hint2</choicehint>
</choice>
<choice correct="false">CC
<choicehint>hint3</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
<label>dropdown</label>
<optionresponse>
<optioninput>
<option correct="False">W1
<optionhint>no</optionhint>
</option>
<option correct="False">W2
<optionhint>nope</optionhint>
</option>
<option correct="True">C1
<optionhint>yes</optionhint>
</option>
</optioninput>
</optionresponse>
<demandhint>
<hint>aaa</hint>
<hint>bbb</hint>
<hint>ccc</hint>
</demandhint>
</problem>
""")
......@@ -832,18 +858,19 @@ describe 'Markdown to xml extended hint with tricky syntax cases', ->
""")
expect(data).toXMLEqual("""
<problem>
<multiplechoiceresponse>
<label>á and Ø</label>
<choicegroup label="á and Ø" type="MultipleChoice">
<choice correct="true">Ø <choicehint>Ø</choicehint>
</choice>
<choice correct="false">BB</choice>
</choicegroup>
</multiplechoiceresponse>
<demandhint>
<hint>Ø</hint>
</demandhint>
<multiplechoiceresponse>
<label>á and Ø</label>
<choicegroup type="MultipleChoice">
<choice correct="true">Ø
<choicehint>Ø</choicehint>
</choice>
<choice correct="false">BB</choice>
</choicegroup>
</multiplechoiceresponse>
<demandhint>
<hint>Ø</hint>
</demandhint>
</problem>
""")
......@@ -856,17 +883,17 @@ describe 'Markdown to xml extended hint with tricky syntax cases', ->
""")
expect(data).toXMLEqual("""
<problem>
<multiplechoiceresponse>
<label>"quotes" aren't `fun`</label>
<choicegroup label="&quot;quotes&quot; aren't `fun`" type="MultipleChoice">
<choice correct="false">"hello" <choicehint>isn't</choicehint>
</choice>
<choice correct="true">"isn't" <choicehint>"hello"</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
<multiplechoiceresponse>
<label>"quotes" aren't `fun`</label>
<choicegroup type="MultipleChoice">
<choice correct="false">"hello"
<choicehint>isn't</choicehint>
</choice>
<choice correct="true">"isn't"
<choicehint>"hello"</choicehint>
</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>
""")
......@@ -883,7 +910,7 @@ describe 'Markdown to xml extended hint with tricky syntax cases', ->
<multiplechoiceresponse>
<label>q1</label>
<p>this (x)</p>
<choicegroup label="q1" type="MultipleChoice">
<choicegroup type="MultipleChoice">
<choice correct="false">a <choicehint>(hint)</choicehint>
</choice>
<choice correct="true">b</choice>
......@@ -909,7 +936,7 @@ describe 'Markdown to xml extended hint with tricky syntax cases', ->
<choiceresponse>
<label>q1</label>
<p>this [x]</p>
<checkboxgroup label="q1">
<checkboxgroup>
<choice correct="false">a [square]</choice>
<choice correct="true">b {{ this hint passes through }}</choice>
</checkboxgroup>
......@@ -942,7 +969,7 @@ describe 'Markdown to xml extended hint with tricky syntax cases', ->
<problem>
<optionresponse>
<label>q22</label>
<optioninput label="q22">
<optioninput>
<option correct="True">x <optionhint>hintx these span</optionhint>
</option>
<option correct="False">yy <optionhint label="meh">hinty</optionhint>
......
......@@ -197,7 +197,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
demandHintTags = [];
toXml = `function (markdown) {
var xml = markdown,
i, splits, scriptFlag;
i, splits, makeParagraph;
var responseTypes = [
'optionresponse', 'multiplechoiceresponse', 'stringresponse', 'numericalresponse', 'choiceresponse'
];
......@@ -209,6 +209,20 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
xml = xml.replace(/(^.*?$)(?=\n\=\=+$)/gm, '<h3 class="hd hd-2 problem-header">$1</h3>');
xml = xml.replace(/\n^\=\=+$/gm, '');
// extract question and description(optional)
// >>question||description<< converts to
// <label>question</label> <description>description</description>
xml = xml.replace(/>>([^]+?)<</gm, function(match, questionText) {
var result = questionText.split('||'),
label = '<label>' + result[0] + '</label>' + '\n';
// don't add empty <description> tag
if (result.length === 1 || !result[1]) {
return label;
}
return label + '<description>' + result[1] + '</description>\n'
})
// Pull out demand hints, || a hint ||
var demandhints = '';
xml = xml.replace(/(^\s*\|\|.*?\|\|\s*$\n?)+/gm, function(match) { // $\n
......@@ -515,35 +529,6 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
return selectString;
});
// replace labels
// looks for >>arbitrary text<< and inserts it into the label attribute of the input type directly below the text.
var split = xml.split('\n');
var new_xml = [];
var line, i, curlabel, prevlabel = '';
var didinput = false;
for (i = 0; i < split.length; i++) {
line = split[i];
if (match = line.match(/>>(.*)<</)) {
curlabel = match[1].replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
// extract the question text and convert it to a <p> tag
line = line.replace(/>>(.*?)<</, "<p class='qtitle'>$1</p>");
} else if (line.match(/<\w+response/) && didinput && curlabel == prevlabel) {
// reset label to prevent gobbling up previous one (if multiple questions)
curlabel = '';
didinput = false;
} else if (line.match(/<(textline|optioninput|formulaequationinput|choicegroup|checkboxgroup)/) && curlabel != '' && curlabel != undefined) {
line = line.replace(/<(textline|optioninput|formulaequationinput|choicegroup|checkboxgroup)/, '<$1 label="' + curlabel + '"');
didinput = true;
prevlabel = curlabel;
}
new_xml.push(line);
}
xml = new_xml.join('\n');
// replace code blocks
xml = xml.replace(/\[code\]\n?([^\]]*)\[\/?code\]/gmi, function(match, p1) {
var selectString = '<pre><code>\n' + p1 + '</code></pre>';
......@@ -552,20 +537,23 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
});
// split scripts and preformatted sections, and wrap paragraphs
splits = xml.split(/(\<\/?(?:script|pre).*?\>)/g);
scriptFlag = false;
splits = xml.split(/(\<\/?(?:script|pre|label|description).*?\>)/g);
// Wrap a string by <p> tag when line is not already wrapped by another tag
// true when line is not already wrapped by another tag false otherwise
makeParagraph = true;
for (i = 0; i < splits.length; i += 1) {
if(/\<(script|pre)/.test(splits[i])) {
scriptFlag = true;
if (/\<(script|pre|label|description)/.test(splits[i])) {
makeParagraph = false;
}
if(!scriptFlag) {
if (makeParagraph) {
splits[i] = splits[i].replace(/(^(?!\s*\<|$).*$)/gm, '<p>$1</p>');
}
if(/\<\/(script|pre)/.test(splits[i])) {
scriptFlag = false;
if (/\<\/(script|pre|label|description)/.test(splits[i])) {
makeParagraph = true;
}
}
......@@ -600,11 +588,6 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
return;
}
// replace <p> tag for question title with <label> tag
if (child.hasAttribute('class') && child.getAttribute('class') === 'qtitle') {
child = $('<label>' + child.textContent + '</label>')[0];
}
if (beforeInputtype) {
// safe-lint: disable=javascript-jquery-insert-into-target
responseType[0].insertBefore(child, inputtype);
......
......@@ -8,15 +8,13 @@ metadata:
You can use the following example problem as a model.
>>The following languages are in the Indo-European family:<<
>>The following languages are in the Indo-European family:||Make sure you select all of the correct options—there may be more than one!<<
[x] Urdu
[ ] Finnish
[x] Marathi
[x] French
[ ] Hungarian
Note: Make sure you select all of the correct options—there may be more than one!
[explanation]
Urdu, Marathi, and French are all Indo-European languages, while Finnish and Hungarian are in the Uralic family.
[explanation]
......@@ -28,14 +26,14 @@ data: |
<p>When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>You can use the following example problem as a model.</p>
<label>The following languages are in the Indo-European family:</label>
<checkboxgroup label="The following languages are in the Indo-European family:">
<description>Make sure you select all of the correct options—there may be more than one!</description>
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
<choice correct="true">French</choice>
<choice correct="false">Hungarian</choice>
</checkboxgroup>
<p>Note: Make sure you select all of the correct options—there may be more than one!</p>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -13,7 +13,7 @@ metadata:
Use the following example problem as a model.
>>Which of the following is a fruit? Check all that apply.<<
>>Which of the following is a fruit?||Make sure you select all of the correct options—there may be more than one!<<
[x] apple {{ selected: You are correct that an apple is a fruit because it is the fertilized ovary that comes from an apple tree and contains seeds. }, { unselected: Remember that an apple is also a fruit.}}
[x] pumpkin {{ selected: You are correct that a pumpkin is a fruit because it is the fertilized ovary of a squash plant and contains seeds. }, { unselected: Remember that a pumpkin is also a fruit.}}
......@@ -36,8 +36,9 @@ data: |
<p>You can also add hints for learners.</p>
<p>Be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>Use the following example problem as a model.</p>
<label>Which of the following is a fruit? Check all that apply.</label>
<checkboxgroup label="Which of the following is a fruit? Check all that apply.">
<label>Which of the following is a fruit?</label>
<description>Make sure you select all of the correct options—there may be more than one!</description>
<checkboxgroup>
<choice correct="true">apple
<choicehint selected="true">You are correct that an apple is a fruit because it is the fertilized ovary that comes from an apple tree and contains seeds.</choicehint>
<choicehint selected="false">Remember that an apple is also a fruit.</choicehint>
......
......@@ -41,8 +41,8 @@ data: |
</script>
<label>Enter two integers that sum to 10.</label>
<textline size="40" correct_answer="3" label="Integer #1"/><br/>
<textline size="40" correct_answer="7" label="Integer #2"/>
<textline size="40" correct_answer="3"/><br/>
<textline size="40" correct_answer="7"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......@@ -64,8 +64,8 @@ data: |
</script>
<label>Enter two integers that sum to 20.</label>
<textline size="40" correct_answer="11" label="Integer #1"/><br/>
<textline size="40" correct_answer="9" label="Integer #2"/>
<textline size="40" correct_answer="11"/><br/>
<textline size="40" correct_answer="9"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -34,8 +34,9 @@ data: |
<formularesponse type="ci" samples="R_1,R_2,R_3@1,2,3:3,4,5#10" answer="$VoVi">
<label>Write an expression for the product of \( R_1\), \( R_2\), and the inverse of \( R_3\).</label>
<description>Enter the equation</description>
<responseparam type="tolerance" default="0.00001"/>
<formulaequationinput size="40" label="Enter the equation"/>
<formulaequationinput size="40"/>
</formularesponse>
<script type="loncapa/python">
......@@ -48,7 +49,8 @@ data: |
<formularesponse type="ci" samples="x,n@1,2:3,4#10" answer="$derivative">
<label>Let \( x\) be a variable, and let \( n\) be an arbitrary constant. What is the derivative of \( x^n\)?</label>
<description>Enter the equation</description>
<responseparam type="tolerance" default="0.00001"/>
<formulaequationinput size="40" label="Enter the equation"/>
<formulaequationinput size="40"/>
</formularesponse>
</problem>
......@@ -159,7 +159,7 @@ data: |
<label>What was the first post-secondary school in China to allow both male and female students?</label>
<additional_answer>National Central University</additional_answer>
<additional_answer>Nanjing University</additional_answer>
<textline label="What was the first post-secondary school in China to allow both male and female students?" size="40"/>
<textline size="40"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......@@ -170,15 +170,15 @@ data: |
<br/>
<p><strong>Example Custom Python-Evaluated Input Problem</strong></p>
<customresponse cfn="test_add_to_ten">
<script type="loncapa/python">
def test_add_to_ten(expect, ans):
return test_add(10, ans)
</script>
<label>Enter two integers that sum to 10.</label>
<textline size="40" correct_answer="3" label="Integer #1"/><br/>
<textline size="40" correct_answer="7" label="Integer #2"/>
<textline size="40" correct_answer="3"/><br/>
<textline size="40" correct_answer="7"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......@@ -198,8 +198,8 @@ data: |
return False
</script>
<label>Enter two integers that sum to 20.</label>
<textline size="40" correct_answer="11" label="Integer #1"/><br/>
<textline size="40" correct_answer="9" label="Integer #2"/>
<textline size="40" correct_answer="11"/><br/>
<textline size="40" correct_answer="9"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -8,7 +8,7 @@ metadata:
You can use the following example problem as a model.
>>Which of the following countries has the largest population?<<
>>Which of the following countries has the largest population?||You can select only one option.<<
( ) Brazil {{ timely feedback -- explain why an almost correct answer is wrong }}
( ) Germany
(x) Indonesia
......@@ -29,7 +29,8 @@ data: |
<p>When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>You can use the following example problem as a model.</p>
<label>Which of the following countries has the largest population?</label>
<choicegroup label="Which of the following countries has the largest population?" type="MultipleChoice">
<description>You can select only one option.</description>
<choicegroup type="MultipleChoice">
<choice correct="false">Brazil
<choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint>
</choice>
......
......@@ -11,7 +11,7 @@ metadata:
Use the following example problem as a model.
>>Which of the following is a vegetable?<<
>>Which of the following is a vegetable?||You can select only one option.<<
( ) apple {{An apple is the fertilized ovary that comes from an apple tree and contains seeds, meaning it is a fruit.}}
( ) pumpkin {{A pumpkin is the fertilized ovary of a squash plant and contains seeds, meaning it is a fruit.}}
(x) potato {{A potato is an edible part of a plant in tuber form and is a vegetable.}}
......@@ -29,7 +29,8 @@ data: |
<p>Be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>Use the following example problem as a model.</p>
<label>Which of the following is a vegetable?</label>
<choicegroup label="Which of the following is a vegetable?" type="MultipleChoice">
<description>You can select only one option.</description>
<choicegroup>
<choice correct="false">apple
<choicehint>An apple is the fertilized ovary that comes from an apple tree and contains seeds, meaning it is a fruit.</choicehint>
</choice>
......
......@@ -10,7 +10,7 @@ metadata:
You can use the following example problems as models.
>>How many miles away from Earth is the sun? Use scientific notation to answer.<<
>>How many miles away from Earth is the sun?||Use scientific notation to answer.<<
= 9.3*10^7
or= 9.296*10^7
......@@ -21,7 +21,7 @@ metadata:
---
>>The square of what number is -100?<<
>>The square of what number is -100?||Use scientific notation to answer.<<
= 10*i
......@@ -37,8 +37,9 @@ data: |
for information about how to enter text into the field.</p>
<p>When you add the problem, be sure to select <strong>Settings</strong> to specify a <strong>Display Name</strong> and other values that apply.</p>
<p>You can use the following example problems as models.</p>
<label>How many miles away from Earth is the sun? Use scientific notation to answer.</label>
<formulaequationinput label="How many million miles are between Earth and the sun? Use scientific notation to answer."/>
<label>How many miles away from Earth is the sun?</label>
<description>Use scientific notation to answer.</description>
<formulaequationinput/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......@@ -49,7 +50,8 @@ data: |
<numericalresponse answer="10*i">
<label>The square of what number is -100?</label>
<formulaequationinput label="The square of what number is -100?"/>
<description>Use scientific notation to answer.</description>
<formulaequationinput/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -13,7 +13,7 @@ metadata:
Use the following example problem as a model.
>>What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)<<
>>What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)||Use scientific notation to answer.<<
= 4 {{The mean for this set of numbers is 20 / 5, which equals 4.}}
......@@ -34,7 +34,8 @@ data: |
<p>Be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>Use the following example problem as a model.</p>
<label>What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)</label>
<formulaequationinput label="What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)"/>
<description>Use scientific notation to answer.</description>
<formulaequationinput/>
<correcthint>The mean for this set of numbers is 20 / 5, which equals 4.</correcthint>
<solution>
<div class="detailed-solution">
......
......@@ -8,7 +8,7 @@ metadata:
You can use the following example problem as a model.
>>Which of the following countries celebrates its independence on August 15?<<
>>Which of the following countries celebrates its independence on August 15?||You can select only one option.<<
[[(India), Spain, China, Bermuda]]
......@@ -22,7 +22,8 @@ data: |
<p>When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>You can use the following example problem as a model.</p>
<label>Which of the following countries celebrates its independence on August 15?</label>
<optioninput label="Which of the following countries celebrates its independence on August 15?" options="('India','Spain','China','Bermuda')" correct="India"/>
<description>You can select only one option.</description>
<optioninput options="('India','Spain','China','Bermuda')" correct="India"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -11,7 +11,7 @@ metadata:
Use the following example problem as a model.
>> A/an ________ is a vegetable.<<
>> A/an ________ is a vegetable.||You can select only one option.<<
[[
apple {{An apple is the fertilized ovary that comes from an apple tree and contains seeds, meaning it is a fruit.}}
......@@ -32,7 +32,8 @@ data: |
<p>Be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>Use the following example problem as a model.</p>
<label>A/an ________ is a vegetable.</label>
<optioninput label=" A/an ________ is a vegetable.">
<description>You can select only one option.</description>
<optioninput>
<option correct="False">apple
<optionhint>An apple is the fertilized ovary that comes from an apple tree and contains seeds, meaning it is a fruit.</optionhint>
</option>
......
......@@ -8,7 +8,7 @@ metadata:
You can use the following example problem as a model.
>>What was the first post-secondary school in China to allow both male and female students?<<
>>What was the first post-secondary school in China to allow both male and female students?||Be sure to check your spelling.<<
= Nanjing Higher Normal Institute
or= National Central University
......@@ -25,9 +25,10 @@ data: |
<p>When you add the problem, be sure to select <strong>Settings</strong> to specify a <strong>Display Name</strong> and other values that apply.</p>
<p>You can use the following example problem as a model.</p>
<label>What was the first post-secondary school in China to allow both male and female students?</label>
<description>Be sure to check your spelling.</description>
<additional_answer>National Central University</additional_answer>
<additional_answer>Nanjing University</additional_answer>
<textline label="What was the first post-secondary school in China to allow both male and female students?" size="40"/>
<textline size="40"/>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -11,7 +11,7 @@ metadata:
Use the following example problem as a model.
>>Which U.S. state has the largest land area?<<
>>Which U.S. state has the largest land area?||Be sure to check your spelling.<<
=Alaska {{Alaska is 576,400 square miles, more than double the land area
of the second largest state, Texas.}}
......@@ -32,10 +32,11 @@ data: |
<p>Be sure to select Settings to specify a Display Name and other values that apply.</p>
<p>Use the following example problem as a model.</p>
<label>Which U.S. state has the largest land area?</label>
<description>Be sure to check your spelling.</description>
<correcthint>Alaska is 576,400 square miles, more than double the land area of the second largest state, Texas.</correcthint>
<stringequalhint answer="Texas">While many people think Texas is the largest state, it is actually the second largest, with 261,797 square miles.</stringequalhint>
<stringequalhint answer="California">California is the third largest state, with 155,959 square miles.</stringequalhint>
<textline label="Which U.S. state has the largest land area?" size="20"/>
<textline size="20"/>
</stringresponse>
<demandhint>
<hint>Consider the square miles, not population.</hint>
......
......@@ -21,6 +21,7 @@ from webob.multidict import MultiDict
import xmodule
from xmodule.tests import DATA_DIR
from capa import responsetypes
from capa.capa_problem import DEFAULT_QUESTION_TEXT
from capa.responsetypes import (StudentInputError, LoncapaProblemError,
ResponseError)
from capa.xqueue_interface import XQueueInterface
......@@ -1762,7 +1763,7 @@ class CapaDescriptorTest(unittest.TestCase):
<p>The following languages are in the Indo-European family:</p>
<choiceresponse>
<checkboxgroup label="The following languages are in the Indo-European family:">
<checkboxgroup>
<choice correct="true">Urdu</choice>
<choice correct="false">Finnish</choice>
<choice correct="true">Marathi</choice>
......@@ -1797,7 +1798,7 @@ class CapaDescriptorTest(unittest.TestCase):
<optionresponse>
<optioninput label="lbl" options="('India','Spain','China','Bermuda')" correct="India"></optioninput>
<optioninput options="('India','Spain','China','Bermuda')" correct="India"></optioninput>
</optionresponse>
<solution>
......@@ -1822,7 +1823,7 @@ class CapaDescriptorTest(unittest.TestCase):
<p>Which of the following countries has the largest population?</p>
<multiplechoiceresponse>
<choicegroup label="Which of the following countries has the largest population?" type="MultipleChoice">
<choicegroup type="MultipleChoice">
<choice correct="false">Brazil
<choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint>
</choice>
......@@ -1866,14 +1867,13 @@ class CapaDescriptorTest(unittest.TestCase):
<p>How many miles away from Earth is the sun? Use scientific notation to answer.</p>
<numericalresponse answer="9.3*10^7">
<formulaequationinput label="How many miles away from Earth is the sun?
Use scientific notation to answer." />
<formulaequationinput/>
</numericalresponse>
<p>The square of what number is -100?</p>
<numericalresponse answer="10*i">
<formulaequationinput label="The square of what number is -100?" />
<formulaequationinput/>
</numericalresponse>
<solution>
......@@ -1906,8 +1906,7 @@ class CapaDescriptorTest(unittest.TestCase):
<stringresponse answer="Nanjing Higher Normal Institute" type="ci" >
<additional_answer answer="National Central University"></additional_answer>
<additional_answer answer="Nanjing University"></additional_answer>
<textline label="What was the first post-secondary school in China to allow both male and female
students?" size="20"/>
<textline size="20"/>
</stringresponse>
<solution>
......@@ -1939,7 +1938,7 @@ class CapaDescriptorTest(unittest.TestCase):
<p>Which of the following is a fruit? Check all that apply.</p>
<choiceresponse>
<checkboxgroup label="Which of the following is a fruit? Check all that apply.">
<checkboxgroup>
<choice correct="true">apple
<choicehint selected="true">You are correct that an apple is a fruit because it is the fertilized
ovary that comes from an apple tree and contains seeds.</choicehint>
......@@ -1987,7 +1986,7 @@ class CapaDescriptorTest(unittest.TestCase):
<p> A/an ________ is a vegetable.</p>
<optionresponse>
<optioninput label=" A/an ________ is a vegetable.">
<optioninput>
<option correct="False">apple <optionhint>An apple is the fertilized ovary that comes from an apple
tree and contains seeds, meaning it is a fruit.</optionhint></option>
<option correct="False">pumpkin <optionhint>A pumpkin is the fertilized ovary of a squash plant and
......@@ -2019,7 +2018,7 @@ class CapaDescriptorTest(unittest.TestCase):
<p>Which of the following is a vegetable?</p>
<multiplechoiceresponse>
<choicegroup label="Which of the following is a vegetable?" type="MultipleChoice">
<choicegroup type="MultipleChoice">
<choice correct="false">apple <choicehint>An apple is the fertilized ovary that comes from an apple
tree and contains seeds, meaning it is a fruit.</choicehint></choice>
<choice correct="false">pumpkin <choicehint>A pumpkin is the fertilized ovary of a squash plant and
......@@ -2056,8 +2055,7 @@ class CapaDescriptorTest(unittest.TestCase):
<p>What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)</p>
<numericalresponse answer="4">
<formulaequationinput label="What is the arithmetic mean for the following set of numbers?
(1, 5, 6, 3, 5)" />
<formulaequationinput/>
<correcthint>The mean for this set of numbers is 20 / 5, which equals 4.</correcthint>
</numericalresponse>
<solution>
......@@ -2098,7 +2096,7 @@ class CapaDescriptorTest(unittest.TestCase):
second largest, with 261,797 square miles.</stringequalhint>
<stringequalhint answer="California">California is the third largest state, with 155,959 square miles.
</stringequalhint>
<textline label="Which U.S. state has the largest land area?" size="20"/>
<textline size="20"/>
</stringresponse>
<demandhint>
......@@ -2175,7 +2173,7 @@ class CapaDescriptorTest(unittest.TestCase):
</choicegroup>
</multiplechoiceresponse>
<optionresponse>
<optioninput label="Option" options="('1','2')" correct="2"></optioninput>
<optioninput options="('1','2')" correct="2"></optioninput>
</optionresponse>
</problem>
""")
......@@ -2557,12 +2555,13 @@ class TestProblemCheckTracking(unittest.TestCase):
def test_choice_answer_text(self):
xml = """\
<problem display_name="Multiple Choice Questions">
<p>What color is the open ocean on a sunny day?</p>
<optionresponse>
<optioninput options="('yellow','blue','green')" correct="blue" label="What color is the open ocean on a sunny day?"/>
<label>What color is the open ocean on a sunny day?</label>
<optioninput options="('yellow','blue','green')" correct="blue"/>
</optionresponse>
<p>Which piece of furniture is built for sitting?</p>
<multiplechoiceresponse>
<label>Which piece of furniture is built for sitting?</label>
<choicegroup type="MultipleChoice">
<choice correct="false"><text>a table</text></choice>
<choice correct="false"><text>a desk</text></choice>
......@@ -2570,9 +2569,10 @@ class TestProblemCheckTracking(unittest.TestCase):
<choice correct="false"><text>a bookshelf</text></choice>
</choicegroup>
</multiplechoiceresponse>
<p>Which of the following are musical instruments?</p>
<choiceresponse>
<checkboxgroup label="Which of the following are musical instruments?">
<label>Which of the following are musical instruments?</label>
<checkboxgroup>
<choice correct="true">a piano</choice>
<choice correct="false">a tree</choice>
<choice correct="true">a guitar</choice>
......@@ -2604,7 +2604,7 @@ class TestProblemCheckTracking(unittest.TestCase):
'variant': '',
},
factory.answer_key(3): {
'question': '',
'question': 'Which piece of furniture is built for sitting?',
'answer': u'<text>a table</text>',
'response_type': 'multiplechoiceresponse',
'input_type': 'choicegroup',
......@@ -2652,7 +2652,7 @@ class TestProblemCheckTracking(unittest.TestCase):
event = self.get_event_for_answers(module, answer_input_dict)
self.assertEquals(event['submission'], {
factory.answer_key(2): {
'question': '',
'question': DEFAULT_QUESTION_TEXT,
'answer': '3.14',
'response_type': 'numericalresponse',
'input_type': 'textline',
......@@ -2683,7 +2683,7 @@ class TestProblemCheckTracking(unittest.TestCase):
event = self.get_event_for_answers(module, answer_input_dict)
self.assertEquals(event['submission'], {
factory.answer_key(2, 1): {
'question': '',
'question': DEFAULT_QUESTION_TEXT,
'answer': 'blue',
'response_type': 'optionresponse',
'input_type': 'optioninput',
......@@ -2691,7 +2691,7 @@ class TestProblemCheckTracking(unittest.TestCase):
'variant': '',
},
factory.answer_key(2, 2): {
'question': '',
'question': DEFAULT_QUESTION_TEXT,
'answer': 'yellow',
'response_type': 'optionresponse',
'input_type': 'optioninput',
......@@ -2748,7 +2748,7 @@ class TestProblemCheckTracking(unittest.TestCase):
event = self.get_event_for_answers(module, answer_input_dict)
self.assertEquals(event['submission'], {
factory.answer_key(2, 1): {
'question': '',
'question': DEFAULT_QUESTION_TEXT,
'answer': 'apple',
'response_type': 'optionresponse',
'input_type': 'optioninput',
......@@ -2756,7 +2756,7 @@ class TestProblemCheckTracking(unittest.TestCase):
'variant': '',
},
factory.answer_key(2, 2): {
'question': '',
'question': DEFAULT_QUESTION_TEXT,
'answer': 'cucumber',
'response_type': 'optionresponse',
'input_type': 'optioninput',
......@@ -2776,7 +2776,7 @@ class TestProblemCheckTracking(unittest.TestCase):
event = self.get_event_for_answers(module, answer_input_dict)
self.assertEquals(event['submission'], {
factory.answer_key(2): {
'question': '',
'question': DEFAULT_QUESTION_TEXT,
'answer': '3.14',
'response_type': 'numericalresponse',
'input_type': 'textline',
......
......@@ -221,3 +221,17 @@ class ProblemPage(PageObject):
if not self.q(xpath=xpath.format(choice)).is_present():
return False
return True
@property
def problem_question(self):
"""
Return the question text of the problem.
"""
return self.q(css="div.problem .wrapper-problem-response legend").text[0]
@property
def problem_question_descriptions(self):
"""
Return a list of question descriptions of the problem.
"""
return self.q(css="div.problem .wrapper-problem-response .question-description").text
......@@ -71,9 +71,9 @@ class EntranceExamPassTest(EntranceExamTest):
"""
xml = dedent("""
<problem>
<p>What is height of eiffel tower without the antenna?.</p>
<multiplechoiceresponse>
<choicegroup label="What is height of eiffel tower without the antenna?" type="MultipleChoice">
<label>What is height of eiffel tower without the antenna?.</label>
<choicegroup type="MultipleChoice">
<choice correct="false">324 meters<choicehint>Antenna is 24 meters high</choicehint></choice>
<choice correct="true">300 meters</choice>
<choice correct="false">224 meters</choice>
......
......@@ -4,6 +4,7 @@ Bok choy acceptance tests for problems in the LMS
See also old lettuce tests in lms/djangoapps/courseware/features/problems.feature
"""
from nose.plugins.attrib import attr
from textwrap import dedent
from common.test.acceptance.tests.helpers import UniqueCourseTest
......@@ -77,7 +78,8 @@ class ProblemClarificationTest(ProblemsTest):
<clarification>Return on Investment <strong>(per year)</strong></clarification> over 20 years.
</p>
<numericalresponse answer="6.5">
<textline label="Enter the annual ROI" trailing_text="%" />
<label>Enter the annual ROI</label>
<textline trailing_text="%" />
</numericalresponse>
</text>
</problem>
......@@ -263,7 +265,8 @@ class ProblemWithMathjax(ProblemsTest):
<problem>
<p>Check mathjax has rendered [mathjax]E=mc^2[/mathjax]</p>
<multiplechoiceresponse>
<choicegroup label="Answer this?" type="MultipleChoice">
<label>Answer this?</label>
<choicegroup type="MultipleChoice">
<choice correct="true">Choice1 <choicehint>Correct choice message</choicehint></choice>
<choice correct="false">Choice2<choicehint>Wrong choice message</choicehint></choice>
</choicegroup>
......@@ -310,7 +313,8 @@ class ProblemPartialCredit(ProblemsTest):
<problem>
<p>The answer is 1. Partial credit for -1.</p>
<numericalresponse answer="1" partial_credit="list">
<formulaequationinput label="How many miles away from Earth is the sun? Use scientific notation to answer." />
<label>How many miles away from Earth is the sun? Use scientific notation to answer.</label>
<formulaequationinput/>
<responseparam type="tolerance" default="0.01" />
<responseparam partial_answers="-1" />
</numericalresponse>
......@@ -343,9 +347,9 @@ class LogoutDuringAnswering(ProblemsTest):
"""
xml = dedent("""
<problem>
<p>The answer is 1</p>
<numericalresponse answer="1">
<formulaequationinput label="where are the songs of spring?" />
<label>The answer is 1</label>
<formulaequationinput/>
<responseparam type="tolerance" default="0.01" />
</numericalresponse>
</problem>
......@@ -412,3 +416,94 @@ class LogoutDuringAnswering(ProblemsTest):
self.assertTrue(problem_page.is_browser_on_page())
self.assertEqual(problem_page.problem_name, 'TEST PROBLEM')
class ProblemQuestionDescriptionTest(ProblemsTest):
"""TestCase Class to verify question and description rendering."""
descriptions = [
"A vegetable is an edible part of a plant in tuber form.",
"A fruit is a fertilized ovary of a plant and contains seeds."
]
def get_problem(self):
"""
Create a problem with question and description.
"""
xml = dedent("""
<problem>
<choiceresponse>
<label>Eggplant is a _____?</label>
<description>{}</description>
<description>{}</description>
<checkboxgroup>
<choice correct="true">vegetable</choice>
<choice correct="false">fruit</choice>
</checkboxgroup>
</choiceresponse>
</problem>
""".format(*self.descriptions))
return XBlockFixtureDesc('problem', 'Label with Description', data=xml)
def test_question_with_description(self):
"""
Scenario: Test that question and description are rendered as expected.
Given I am enrolled in a course.
When I visit a unit page with a CAPA question.
Then label and description should be rendered correctly.
"""
self.courseware_page.visit()
problem_page = ProblemPage(self.browser)
problem_page.wait_for_element_visibility(problem_page.CSS_PROBLEM_HEADER, 'wait for problem header')
self.assertEqual(problem_page.problem_name, 'Label with Description')
self.assertEqual(problem_page.problem_question, 'Eggplant is a _____?')
self.assertEqual(problem_page.problem_question_descriptions, self.descriptions)
@attr('a11y')
class CAPAProblemQuestionDescriptionA11yTest(ProblemsTest):
"""TestCase Class to verify CAPA problem questions accessibility."""
def get_problem(self):
"""
Problem structure.
"""
xml = dedent("""
<problem>
<choiceresponse>
<label>question 1 text here</label>
<description>description 2 text 1</description>
<description>description 2 text 2</description>
<checkboxgroup>
<choice correct="true">True</choice>
<choice correct="false">False</choice>
</checkboxgroup>
</choiceresponse>
<multiplechoiceresponse>
<label>question 2 text here</label>
<description>description 2 text 1</description>
<description>description 2 text 2</description>
<choicegroup type="MultipleChoice">
<choice correct="false">Alpha <choicehint>A hint</choicehint></choice>
<choice correct="true">Beta</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>
""")
return XBlockFixtureDesc('problem', 'Problem A11Y TEST', data=xml)
def test_a11y(self):
"""
Scenario: Verifies that each question and description has unique id.
Given I am enrolled in a course.
And I visit a unit page with two CAPA problems
Then I check question and description has unique IDs
"""
self.courseware_page.visit()
problem_page = ProblemPage(self.browser)
# Set the scope to the problem question
problem_page.a11y_audit.config.set_scope(
include=['section.wrapper-problem-response']
)
# Run the accessibility audit.
problem_page.a11y_audit.check_for_accessibility_errors()
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