Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
problem-builder
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
problem-builder
Commits
2885f774
Commit
2885f774
authored
Oct 22, 2015
by
E. Kolpakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Making MCQ use message attribute the same way MRQ does
parent
f236debd
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
94 additions
and
67 deletions
+94
-67
problem_builder/mcq.py
+1
-0
problem_builder/public/js/questionnaire.js
+21
-16
problem_builder/tests/integration/base_test.py
+17
-0
problem_builder/tests/integration/test_mentoring.py
+3
-3
problem_builder/tests/integration/test_questionnaire.py
+48
-46
problem_builder/tests/integration/xml/mcq_1.xml
+4
-2
No files found.
problem_builder/mcq.py
View file @
2885f774
...
...
@@ -99,6 +99,7 @@ class MCQBlock(SubmittingXBlockMixin, QuestionnaireAbstractBlock):
return
{
'submission'
:
submission
,
'message'
:
self
.
message
,
'status'
:
'correct'
if
correct
else
'incorrect'
,
'tips'
:
formatted_tips
,
'weight'
:
self
.
weight
,
...
...
problem_builder/public/js/questionnaire.js
View file @
2885f774
// TODO: Split in two files
function
display_message
(
message
,
messageView
,
checkmark
){
if
(
message
)
{
var
msg
=
'<div class="message-content">'
+
message
+
'</div>'
+
'<div class="close icon-remove-sign fa-times-circle"></div>'
;
messageView
.
showMessage
(
msg
);
if
(
checkmark
)
{
checkmark
.
addClass
(
'checkmark-clickable'
);
checkmark
.
on
(
'click'
,
function
(
ev
)
{
ev
.
stopPropagation
();
messageView
.
showMessage
(
msg
);
})
}
}
}
function
MessageView
(
element
,
mentoring
)
{
return
{
messageDOM
:
$
(
'.feedback'
,
element
),
...
...
@@ -102,13 +117,15 @@ function MCQBlock(runtime, element) {
$
(
'.choice input'
,
element
).
prop
(
'disabled'
,
true
);
},
handleSubmit
:
function
(
result
)
{
handleSubmit
:
function
(
result
,
options
)
{
mentoring
=
this
.
mentoring
;
var
mentoring
=
this
.
mentoring
;
var
messageView
=
MessageView
(
element
,
mentoring
);
messageView
.
clearResult
();
display_message
(
result
.
message
,
messageView
,
options
.
checkmark
);
var
choiceInputs
=
$
(
'.choice-selector input'
,
element
);
$
.
each
(
choiceInputs
,
function
(
index
,
choiceInput
)
{
var
choiceInputDOM
=
$
(
choiceInput
);
...
...
@@ -127,7 +144,6 @@ function MCQBlock(runtime, element) {
if
(
result
.
tips
&&
choiceInputDOM
.
val
()
===
result
.
submission
)
{
mentoring
.
setContent
(
choiceTipsDOM
,
result
.
tips
);
messageView
.
showMessage
(
choiceTipsDOM
);
}
choiceResultDOM
.
off
(
'click'
).
on
(
'click'
,
function
()
{
...
...
@@ -187,22 +203,11 @@ function MRQBlock(runtime, element) {
handleSubmit
:
function
(
result
,
options
)
{
mentoring
=
this
.
mentoring
;
var
mentoring
=
this
.
mentoring
;
var
messageView
=
MessageView
(
element
,
mentoring
);
if
(
result
.
message
)
{
var
msg
=
'<div class="message-content">'
+
result
.
message
+
'</div>'
+
'<div class="close icon-remove-sign fa-times-circle"></div>'
;
messageView
.
showMessage
(
msg
);
if
(
options
.
checkmark
)
{
options
.
checkmark
.
addClass
(
'checkmark-clickable'
);
options
.
checkmark
.
on
(
'click'
,
function
(
ev
)
{
ev
.
stopPropagation
();
messageView
.
showMessage
(
msg
);
})
}
}
display_message
(
result
.
message
,
messageView
,
options
.
checkmark
);
var
questionnaireDOM
=
$
(
'fieldset.questionnaire'
,
element
);
var
data
=
questionnaireDOM
.
data
();
...
...
problem_builder/tests/integration/base_test.py
View file @
2885f774
...
...
@@ -17,6 +17,7 @@
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
import
mock
from
xblock.fields
import
String
from
xblockutils.base_test
import
SeleniumBaseTest
,
SeleniumXBlockTest
...
...
@@ -99,6 +100,22 @@ class MentoringBaseTest(SeleniumBaseTest, PopupCheckMixin):
module_name
=
__name__
default_css_selector
=
'div.mentoring'
__asides_patch
=
None
@classmethod
def
setUpClass
(
cls
):
super
(
MentoringBaseTest
,
cls
)
.
setUpClass
()
cls
.
__asides_patch
=
mock
.
patch
(
"workbench.runtime.WorkbenchRuntime.applicable_aside_types"
,
mock
.
Mock
(
return_value
=
[])
)
cls
.
__asides_patch
.
start
()
@classmethod
def
tearDownClass
(
cls
):
cls
.
__asides_patch
.
stop
()
super
(
MentoringBaseTest
,
cls
)
.
tearDownClass
()
class
MentoringAssessmentBaseTest
(
ProblemBuilderBaseTest
):
"""
...
...
problem_builder/tests/integration/test_mentoring.py
View file @
2885f774
...
...
@@ -149,7 +149,7 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
def
_standard_checks
(
self
,
answer
,
mcq
,
mrq
,
rating
,
messages
):
self
.
assertEqual
(
answer
.
get_attribute
(
'value'
),
'This is the answer'
)
self
.
_assert_feedback_showed
(
mcq
,
0
,
"Great!"
)
self
.
_assert_feedback_showed
(
mcq
,
0
,
"Great!"
,
click_choice_result
=
True
)
self
.
_assert_feedback_showed
(
mrq
,
0
,
"This is something everyone has to like about this MRQ"
,
click_choice_result
=
True
...
...
@@ -234,7 +234,7 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
# precondition - verifying 100% score achieved
self
.
assertEqual
(
answer
.
get_attribute
(
'value'
),
'This is the answer'
)
self
.
_assert_feedback_showed
(
mcq
,
0
,
"Great!"
)
self
.
_assert_feedback_showed
(
mcq
,
0
,
"Great!"
,
click_choice_result
=
True
)
self
.
_assert_feedback_showed
(
mrq
,
0
,
"This is something everyone has to like about this MRQ"
,
click_choice_result
=
True
...
...
@@ -275,7 +275,7 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
def
assert_state
(
answer
,
mcq
,
mrq
,
rating
,
messages
):
self
.
assertEqual
(
answer
.
get_attribute
(
'value'
),
'This is the answer'
)
self
.
_assert_feedback_showed
(
mcq
,
0
,
"Great!"
)
self
.
_assert_feedback_showed
(
mcq
,
0
,
"Great!"
,
click_choice_result
=
True
)
self
.
_assert_feedback_showed
(
mrq
,
0
,
"This is something everyone has to like about this MRQ"
,
click_choice_result
=
True
...
...
problem_builder/tests/integration/test_questionnaire.py
View file @
2885f774
...
...
@@ -55,6 +55,9 @@ class QuestionnaireBlockTest(MentoringBaseTest):
self
.
assertEqual
(
messages
.
text
,
''
)
self
.
assertFalse
(
messages
.
find_elements_by_xpath
(
'./*'
))
def
_click_result_icon
(
self
,
choice
):
choice
.
find_element_by_css_selector
(
".choice-result"
)
.
click
()
def
test_mcq_choices_rating
(
self
):
"""
Mentoring MCQ should display tips according to user choice
...
...
@@ -69,14 +72,18 @@ class QuestionnaireBlockTest(MentoringBaseTest):
self
.
assert_messages_empty
(
messages
)
self
.
assertFalse
(
submit
.
is_enabled
())
mcq1_legend
=
mcq1
.
find_element_by_css_selector
(
'legend'
)
mcq2_legend
=
mcq2
.
find_element_by_css_selector
(
'legend'
)
self
.
assertEqual
(
mcq1_legend
.
text
,
'Question 1
\n
Do you like this MCQ?'
)
self
.
assertEqual
(
mcq2_legend
.
text
,
'Question 2
\n
How do you rate this MCQ?'
)
self
.
assertEqual
(
mcq1
.
find_element_by_css_selector
(
'legend'
)
.
text
,
'Question 1
\n
Do you like this MCQ?'
)
self
.
assertEqual
(
mcq2
.
find_element_by_css_selector
(
'legend'
)
.
text
,
'Question 2
\n
How do you rate this MCQ?'
)
mcq1_feedback
=
mcq1
.
find_element_by_css_selector
(
'.feedback'
)
mcq2_feedback
=
mcq2
.
find_element_by_css_selector
(
'.feedback'
)
mcq1_choices
=
mcq1
.
find_elements_by_css_selector
(
'.choices .choice'
)
mcq2_choices
=
mcq2
.
find_elements_by_css_selector
(
'.rating .choice'
)
mcq1_choices_input
=
self
.
_get_inputs
(
mcq1_choices
)
mcq2_choices_input
=
self
.
_get_inputs
(
mcq2_choices
)
self
.
assertListEqual
(
[
self
.
_get_choice_label_text
(
choice
)
for
choice
in
mcq1_choices
],
[
"Yes"
,
"Maybe not"
,
"I don't understand"
]
...
...
@@ -86,31 +93,21 @@ class QuestionnaireBlockTest(MentoringBaseTest):
[
'1 - Not good at all'
,
'2'
,
'3'
,
'4'
,
'5 - Extremely good'
,
"I don't want to rate it"
]
)
mcq1_choices_input
=
self
.
_get_inputs
(
mcq1_choices
)
mcq2_choices_input
=
self
.
_get_inputs
(
mcq2_choices
)
self
.
assertEqual
(
mcq1_choices_input
[
0
]
.
get_attribute
(
'value'
),
'yes'
)
self
.
assertEqual
(
mcq1_choices_input
[
1
]
.
get_attribute
(
'value'
),
'maybenot'
)
self
.
assertEqual
(
mcq1_choices_input
[
2
]
.
get_attribute
(
'value'
),
'understand'
)
self
.
assertEqual
(
mcq2_choices_input
[
0
]
.
get_attribute
(
'value'
),
'1'
)
self
.
assertEqual
(
mcq2_choices_input
[
1
]
.
get_attribute
(
'value'
),
'2'
)
self
.
assertEqual
(
mcq2_choices_input
[
2
]
.
get_attribute
(
'value'
),
'3'
)
self
.
assertEqual
(
mcq2_choices_input
[
3
]
.
get_attribute
(
'value'
),
'4'
)
self
.
assertEqual
(
mcq2_choices_input
[
4
]
.
get_attribute
(
'value'
),
'5'
)
self
.
assertEqual
(
mcq2_choices_input
[
5
]
.
get_attribute
(
'value'
),
'notwant'
)
self
.
assertListEqual
(
[
choice_input
.
get_attribute
(
'value'
)
for
choice_input
in
mcq1_choices_input
],
[
'yes'
,
'maybenot'
,
'understand'
]
)
# Submit button disabled without selecting anything
self
.
assertFalse
(
submit
.
is_enabled
())
self
.
assertListEqual
(
[
choice_input
.
get_attribute
(
'value'
)
for
choice_input
in
mcq2_choices_input
],
[
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'notwant'
]
)
# Submit button stays disabled when there are unfinished mcqs
def
submit_answer_and_assert_messages
(
mcq1_answer
,
mcq2_answer
,
item_feedback1
,
item_feedback2
):
self
.
_selenium_bug_workaround_scroll_to
(
mcq1
)
mcq1_choices_input
[
1
]
.
click
()
self
.
assertFalse
(
submit
.
is_enabled
())
# Should not show full completion message when wrong answers are selected
self
.
_selenium_bug_workaround_scroll_to
(
mcq1
)
mcq1_choices_input
[
0
]
.
click
()
mcq2_choices_input
[
2
]
.
click
()
mcq1_choices_input
[
mcq1_answer
]
.
click
()
mcq2_choices_input
[
mcq2_answer
]
.
click
()
self
.
assertTrue
(
submit
.
is_enabled
())
submit
.
click
()
self
.
wait_until_disabled
(
submit
)
...
...
@@ -118,28 +115,35 @@ class QuestionnaireBlockTest(MentoringBaseTest):
mcq1_tips
=
mcq1
.
find_element_by_css_selector
(
".choice-tips .tip p"
)
mcq2_tips
=
mcq2
.
find_element_by_css_selector
(
".choice-tips .tip p"
)
self
.
assertEqual
(
mcq1_tips
.
text
,
'Great!'
)
self
.
assertTrue
(
mcq1_feedback
.
is_displayed
())
self
.
assertEqual
(
mcq1_feedback
.
text
,
"Feedback message 1"
)
self
.
assertTrue
(
mcq2_feedback
.
is_displayed
())
self
.
assertEqual
(
mcq2_feedback
.
text
,
"Feedback message 2"
)
self
.
assertFalse
(
mcq1_tips
.
is_displayed
())
self
.
assertFalse
(
mcq2_tips
.
is_displayed
())
self
.
_click_result_icon
(
mcq1_choices
[
mcq1_answer
])
self
.
assertEqual
(
mcq1_tips
.
text
,
item_feedback1
)
self
.
assertTrue
(
mcq1_tips
.
is_displayed
())
self
.
assertEqual
(
mcq2_tips
.
text
,
'Will do better next time...'
)
self
.
_click_result_icon
(
mcq2_choices
[
mcq2_answer
])
self
.
assertEqual
(
mcq2_tips
.
text
,
item_feedback2
)
self
.
assertTrue
(
mcq2_tips
.
is_displayed
())
self
.
assertEqual
(
messages
.
text
,
''
)
self
.
assertFalse
(
messages
.
is_displayed
())
# Should show full completion when the right answers are selected
# Submit button disabled without selecting anything
self
.
assertFalse
(
submit
.
is_enabled
())
# Submit button stays disabled when there are unfinished mcqs
self
.
_selenium_bug_workaround_scroll_to
(
mcq1
)
mcq1_choices_input
[
0
]
.
click
()
mcq2_choices_input
[
3
]
.
click
()
self
.
assertTrue
(
submit
.
is_enabled
())
submit
.
click
()
self
.
wait_until_disabled
(
submit
)
mcq1_choices_input
[
1
]
.
click
()
self
.
assertFalse
(
submit
.
is_enabled
())
mcq1_tips
=
mcq1
.
find_element_by_css_selector
(
".choice-tips .tip p"
)
mcq2_tips
=
mcq2
.
find_element_by_css_selector
(
".choice-tips .tip p"
)
# Should not show full completion message when wrong answers are selected
submit_answer_and_assert_messages
(
0
,
2
,
'Great!'
,
'Will do better next time...'
)
self
.
assertEqual
(
messages
.
text
,
''
)
self
.
assertFalse
(
messages
.
is_displayed
())
self
.
assertEqual
(
mcq1_tips
.
text
,
'Great!'
)
self
.
assertTrue
(
mcq1_tips
.
is_displayed
())
self
.
assertEqual
(
mcq2_tips
.
text
,
'I love good grades.'
)
self
.
assertTrue
(
mcq2_tips
.
is_displayed
())
# Should show full completion when the right answers are selected
submit_answer_and_assert_messages
(
0
,
3
,
'Great!'
,
'I love good grades.'
)
self
.
assertIn
(
'All is good now...
\n
Congratulations!'
,
messages
.
text
)
self
.
assertTrue
(
messages
.
is_displayed
())
...
...
@@ -150,6 +154,8 @@ class QuestionnaireBlockTest(MentoringBaseTest):
self
.
assertEqual
(
len
(
mcq2_tip_containers
),
6
)
# Clicking outside the tips should hide the tips and clear the with-tips class.
mcq1_tips
=
mcq1
.
find_element_by_css_selector
(
".choice-tips .tip p"
)
mcq2_tips
=
mcq2
.
find_element_by_css_selector
(
".choice-tips .tip p"
)
mcq1
.
find_element_by_css_selector
(
'.mentoring .question-title'
)
.
click
()
mcq2
.
find_element_by_css_selector
(
'.mentoring .question-title'
)
.
click
()
mcq1_tip_containers
=
mcq1
.
find_elements_by_css_selector
(
'.choice-tips-container.with-tips'
)
...
...
@@ -274,16 +280,12 @@ class QuestionnaireBlockTest(MentoringBaseTest):
submit
.
click
()
self
.
wait_until_disabled
(
submit
)
self
.
_click_result_icon
(
choice_wrapper
)
item_feedback_popup
=
choice_wrapper
.
find_element_by_css_selector
(
".choice-tips"
)
self
.
assertTrue
(
item_feedback_popup
.
is_displayed
())
feedback_height
=
self
.
_get_inner_height
(
item_feedback_popup
)
self
.
assertEqual
(
feedback_height
,
expected_height
)
choice_wrapper
.
find_element_by_css_selector
(
".choice-result"
)
.
click
()
item_feedback_popup
=
choice_wrapper
.
find_element_by_css_selector
(
".choice-tips"
)
item_feedback_height
=
self
.
_get_inner_height
(
item_feedback_popup
)
self
.
assertEqual
(
item_feedback_height
,
expected_height
)
@patch.object
(
MentoringBlock
,
'get_theme'
,
Mock
(
return_value
=
{
'package'
:
'problem_builder'
,
'locations'
:
[
'public/themes/lms.css'
]}))
...
...
problem_builder/tests/integration/xml/mcq_1.xml
View file @
2885f774
<vertical_demo>
<problem-builder
url_name=
"mcq_1"
enforce_dependency=
"false"
>
<pb-mcq
name=
"mcq_1_1"
question=
"Do you like this MCQ?"
correct_choices=
'["yes"]'
>
<pb-mcq
name=
"mcq_1_1"
question=
"Do you like this MCQ?"
correct_choices=
'["yes"]'
message=
"Feedback message 1"
>
<pb-choice
value=
"yes"
>
Yes
</pb-choice>
<pb-choice
value=
"maybenot"
>
Maybe not
</pb-choice>
<pb-choice
value=
"understand"
>
I don't understand
</pb-choice>
...
...
@@ -10,7 +10,9 @@
<pb-tip
values=
'["understand"]'
><div
id=
"test-custom-html"
>
Really?
</div></pb-tip>
</pb-mcq>
<pb-rating
name=
"mcq_1_2"
low=
"Not good at all"
high=
"Extremely good"
question=
"How do you rate this MCQ?"
correct_choices=
'["4","5"]'
>
<pb-rating
name=
"mcq_1_2"
low=
"Not good at all"
high=
"Extremely good"
question=
"How do you rate this MCQ?"
correct_choices=
'["4","5"]'
message=
"Feedback message 2"
>
<pb-choice
value=
"notwant"
>
I don't want to rate it
</pb-choice>
<pb-tip
values=
'["4","5"]'
>
I love good grades.
</pb-tip>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment