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
dd144544
Commit
dd144544
authored
Oct 26, 2015
by
Eugeny Kolpakov
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #81 from open-craft/mcq_messages
Making MCQ use message attribute the same way MRQ does
parents
7cd071d2
2885f774
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
96 additions
and
69 deletions
+96
-69
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
+50
-48
problem_builder/tests/integration/xml/mcq_1.xml
+4
-2
No files found.
problem_builder/mcq.py
View file @
dd144544
...
...
@@ -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 @
dd144544
// 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 @
dd144544
...
...
@@ -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 @
dd144544
...
...
@@ -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 @
dd144544
...
...
@@ -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,18 +93,41 @@ 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
.
assertListEqual
(
[
choice_input
.
get_attribute
(
'value'
)
for
choice_input
in
mcq1_choices_input
],
[
'yes'
,
'maybenot'
,
'understand'
]
)
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
mcq2_choices_input
],
[
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'notwant'
]
)
def
submit_answer_and_assert_messages
(
mcq1_answer
,
mcq2_answer
,
item_feedback1
,
item_feedback2
):
self
.
_selenium_bug_workaround_scroll_to
(
mcq1
)
mcq1_choices_input
[
mcq1_answer
]
.
click
()
mcq2_choices_input
[
mcq2_answer
]
.
click
()
self
.
assertTrue
(
submit
.
is_enabled
())
submit
.
click
()
self
.
wait_until_disabled
(
submit
)
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
.
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
.
_click_result_icon
(
mcq2_choices
[
mcq2_answer
])
self
.
assertEqual
(
mcq2_tips
.
text
,
item_feedback2
)
self
.
assertTrue
(
mcq2_tips
.
is_displayed
())
# Submit button disabled without selecting anything
self
.
assertFalse
(
submit
.
is_enabled
())
...
...
@@ -108,38 +138,12 @@ class QuestionnaireBlockTest(MentoringBaseTest):
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
()
self
.
assertTrue
(
submit
.
is_enabled
())
submit
.
click
()
self
.
wait_until_disabled
(
submit
)
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_tips
.
is_displayed
())
self
.
assertEqual
(
mcq2_tips
.
text
,
'Will do better next time...'
)
self
.
assertTrue
(
mcq2_tips
.
is_displayed
())
submit_answer_and_assert_messages
(
0
,
2
,
'Great!'
,
'Will do better next time...'
)
self
.
assertEqual
(
messages
.
text
,
''
)
self
.
assertFalse
(
messages
.
is_displayed
())
# Should show full completion when the right answers are selected
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_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_tips
.
is_displayed
())
self
.
assertEqual
(
mcq2_tips
.
text
,
'I love good grades.'
)
self
.
assertTrue
(
mcq2_tips
.
is_displayed
())
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 @
dd144544
<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