Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xblock-drag-and-drop-v2
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
xblock-drag-and-drop-v2
Commits
7fd8c2ed
Commit
7fd8c2ed
authored
Jul 19, 2016
by
Matjaz Gregoric
Committed by
GitHub
Jul 19, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #80 from open-craft/mtyaka/remove-numeric-input
Remove support for numerical input
parents
bab49713
1870d6f0
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
55 additions
and
529 deletions
+55
-529
README.md
+8
-15
drag_and_drop_v2/drag_and_drop_v2.py
+7
-54
drag_and_drop_v2/public/css/drag_and_drop.css
+0
-43
drag_and_drop_v2/public/css/drag_and_drop_edit.css
+0
-6
drag_and_drop_v2/public/js/drag_and_drop.js
+6
-93
drag_and_drop_v2/public/js/drag_and_drop_edit.js
+0
-13
drag_and_drop_v2/public/themes/apros.css
+1
-12
drag_and_drop_v2/templates/html/js_templates.html
+0
-18
drag_and_drop_v2/translations/en/LC_MESSAGES/text.po
+0
-13
drag_and_drop_v2/translations/eo/LC_MESSAGES/text.po
+0
-23
tests/integration/data/old_version_data.json
+1
-6
tests/integration/data/test_data.json
+1
-5
tests/integration/data/test_data_other.json
+1
-5
tests/integration/data/test_html_data.json
+1
-5
tests/integration/test_custom_data_render.py
+0
-1
tests/integration/test_interaction.py
+9
-92
tests/unit/data/html/config_out.json
+4
-8
tests/unit/data/html/data.json
+1
-5
tests/unit/data/old/config_out.json
+0
-4
tests/unit/data/old/data.json
+0
-4
tests/unit/data/plain/config_out.json
+4
-8
tests/unit/data/plain/data.json
+1
-5
tests/unit/test_advanced.py
+3
-84
tests/unit/test_basics.py
+7
-7
No files found.
README.md
View file @
7fd8c2ed
...
@@ -13,7 +13,6 @@ The editor is fully guided. Features include:
...
@@ -13,7 +13,6 @@ The editor is fully guided. Features include:
*
custom text and background colors for items
*
custom text and background colors for items
*
optional auto-alignment for items (left, right, center)
*
optional auto-alignment for items (left, right, center)
*
image items
*
image items
*
items prompting for additional (numerical) input after being dropped
*
decoy items that don't have a zone
*
decoy items that don't have a zone
*
feedback popups for both correct and incorrect attempts
*
feedback popups for both correct and incorrect attempts
*
introductory and final feedback
*
introductory and final feedback
...
@@ -135,15 +134,6 @@ after the learner drops the item on a zone - the success feedback is
...
@@ -135,15 +134,6 @@ after the learner drops the item on a zone - the success feedback is
shown if the item is dropped on the correct zone, while the error
shown if the item is dropped on the correct zone, while the error
feedback is shown when dropping the item on an incorrect drop zone.
feedback is shown when dropping the item on an incorrect drop zone.
Additionally, items can have a numerical value (and an optional error
margin) associated with them. When a learner drops an item that has a
numerical value on the correct zone, an input field for entering a
value is shown next to the item. The value that the learner submits is
checked against the expected value for the item. If you also specify a
margin, the value entered by the learner will be considered correct if
it does not differ from the expected value by more than that margin
(and incorrect otherwise).


The zone that an item belongs to is selected from a dropdown that
The zone that an item belongs to is selected from a dropdown that
...
@@ -153,6 +143,13 @@ any zone.
...
@@ -153,6 +143,13 @@ any zone.
You can define an arbitrary number of drag items.
You can define an arbitrary number of drag items.
Demo Course
-----------
Export of a demo course that showcases various Drag and Drop v2
features is available at
[
github.com/open-craft/demo-courses/archive/drag-and-drop-v2.tar.gz
](
https://github.com/open-craft/demo-courses/archive/drag-and-drop-v2.tar.gz
)
.
Analytics Events
Analytics Events
----------------
----------------
...
@@ -261,9 +258,7 @@ Example ("common" fields that are not interesting in this context have been left
...
@@ -261,9 +258,7 @@ Example ("common" fields that are not interesting in this context have been left
{
{
...
...
"event": {
"event": {
"input": null,
"is_correct": true, -- Whether the draggable item has been placed in the correct location.
"is_correct": true, -- False if there is an input in the draggable item, and the learner provided the wrong answer. Otherwise true.
"is_correct_location": true, -- Whether the draggable item has been placed in the correct location.
"item_id": 0, -- ID of the draggable item.
"item_id": 0, -- ID of the draggable item.
"location": "The Top Zone", -- Name of the location the item was dragged to.
"location": "The Top Zone", -- Name of the location the item was dragged to.
},
},
...
@@ -284,11 +279,9 @@ Real event example (taken from a devstack):
...
@@ -284,11 +279,9 @@ Real event example (taken from a devstack):
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"accept_language": "en;q=1.0, en;q=0.5",
"accept_language": "en;q=1.0, en;q=0.5",
"event": {
"event": {
"is_correct_location": true,
"is_correct": true,
"is_correct": true,
"location": "The Top Zone",
"location": "The Top Zone",
"item_id": 0,
"item_id": 0,
"input": null
},
},
"event_source": "server",
"event_source": "server",
"context": {
"context": {
...
...
drag_and_drop_v2/drag_and_drop_v2.py
View file @
7fd8c2ed
...
@@ -167,7 +167,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -167,7 +167,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
for
item
in
items
:
for
item
in
items
:
del
item
[
'feedback'
]
del
item
[
'feedback'
]
del
item
[
'zone'
]
del
item
[
'zone'
]
item
[
'inputOptions'
]
=
'inputOptions'
in
item
# Fall back on "backgroundImage" to be backward-compatible.
# Fall back on "backgroundImage" to be backward-compatible.
image_url
=
item
.
get
(
'imageURL'
)
or
item
.
get
(
'backgroundImage'
)
image_url
=
item
.
get
(
'imageURL'
)
or
item
.
get
(
'backgroundImage'
)
if
image_url
:
if
image_url
:
...
@@ -267,31 +266,13 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -267,31 +266,13 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
feedback
=
item
[
'feedback'
][
'incorrect'
]
feedback
=
item
[
'feedback'
][
'incorrect'
]
overall_feedback
=
None
overall_feedback
=
None
is_correct
=
False
is_correct
=
False
is_correct_location
=
False
if
item
[
'zone'
]
==
attempt
[
'zone'
]:
# Student placed item in correct zone
if
'input'
in
attempt
:
# Student submitted numerical value for item
is_correct
=
True
state
=
self
.
_get_item_state
()
.
get
(
str
(
item
[
'id'
]))
feedback
=
item
[
'feedback'
][
'correct'
]
if
state
:
state
[
'input'
]
=
attempt
[
'input'
]
is_correct_location
=
True
if
self
.
_is_correct_input
(
item
,
attempt
[
'input'
]):
is_correct
=
True
feedback
=
item
[
'feedback'
][
'correct'
]
else
:
is_correct
=
False
elif
item
[
'zone'
]
==
attempt
[
'zone'
]:
# Student placed item in correct zone
is_correct_location
=
True
if
'inputOptions'
in
item
:
# Input value will have to be provided for the item.
# It is not (yet) correct and no feedback should be shown yet.
is_correct
=
False
feedback
=
None
else
:
# If this item has no input value set, we are done with it.
is_correct
=
True
feedback
=
item
[
'feedback'
][
'correct'
]
state
=
{
state
=
{
'zone'
:
attempt
[
'zone'
],
'zone'
:
attempt
[
'zone'
],
'correct'
:
True
,
'x_percent'
:
attempt
[
'x_percent'
],
'x_percent'
:
attempt
[
'x_percent'
],
'y_percent'
:
attempt
[
'y_percent'
],
'y_percent'
:
attempt
[
'y_percent'
],
}
}
...
@@ -325,14 +306,11 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -325,14 +306,11 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
'item_id'
:
item
[
'id'
],
'item_id'
:
item
[
'id'
],
'location'
:
zone
.
get
(
"title"
),
'location'
:
zone
.
get
(
"title"
),
'location_id'
:
zone
.
get
(
"uid"
),
'location_id'
:
zone
.
get
(
"uid"
),
'input'
:
attempt
.
get
(
'input'
),
'is_correct_location'
:
is_correct_location
,
'is_correct'
:
is_correct
,
'is_correct'
:
is_correct
,
})
})
return
{
return
{
'correct'
:
is_correct
,
'correct'
:
is_correct
,
'correct_location'
:
is_correct_location
,
'finished'
:
self
.
_is_finished
(),
'finished'
:
self
.
_is_finished
(),
'overall_feedback'
:
overall_feedback
,
'overall_feedback'
:
overall_feedback
,
'feedback'
:
feedback
'feedback'
:
feedback
...
@@ -396,7 +374,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -396,7 +374,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
item_state
=
self
.
_get_item_state
()
item_state
=
self
.
_get_item_state
()
for
item_id
,
item
in
item_state
.
iteritems
():
for
item_id
,
item
in
item_state
.
iteritems
():
definition
=
self
.
_get_item_definition
(
int
(
item_id
))
definition
=
self
.
_get_item_definition
(
int
(
item_id
))
item
[
'correct_input'
]
=
self
.
_is_correct_input
(
definition
,
item
.
get
(
'input'
))
# If information about zone is missing
# If information about zone is missing
# (because problem was completed before a11y enhancements were implemented),
# (because problem was completed before a11y enhancements were implemented),
# deduce zone in which item is placed from definition:
# deduce zone in which item is placed from definition:
...
@@ -468,8 +445,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -468,8 +445,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
total_count
+=
1
total_count
+=
1
item_id
=
str
(
item
[
'id'
])
item_id
=
str
(
item
[
'id'
])
if
item_id
in
item_state
:
if
item_id
in
item_state
:
if
self
.
_is_correct_input
(
item
,
item_state
[
item_id
]
.
get
(
'input'
)):
correct_count
+=
1
correct_count
+=
1
return
correct_count
/
float
(
total_count
)
*
self
.
weight
return
correct_count
/
float
(
total_count
)
*
self
.
weight
...
@@ -486,11 +462,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -486,11 +462,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
total_count
+=
1
total_count
+=
1
item_id
=
str
(
item
[
'id'
])
item_id
=
str
(
item
[
'id'
])
if
item_id
in
item_state
:
if
item_id
in
item_state
:
if
'inputOptions'
in
item
:
completed_count
+=
1
if
'input'
in
item_state
[
item_id
]:
completed_count
+=
1
else
:
completed_count
+=
1
return
completed_count
==
total_count
return
completed_count
==
total_count
...
@@ -513,25 +485,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
...
@@ -513,25 +485,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
return
usage_id
return
usage_id
@staticmethod
@staticmethod
def
_is_correct_input
(
item
,
val
):
"""
Is submitted numerical value within the tolerated margin for this item.
"""
input_options
=
item
.
get
(
'inputOptions'
)
if
input_options
:
try
:
submitted_value
=
float
(
val
)
except
(
ValueError
,
TypeError
):
return
False
else
:
expected_value
=
input_options
[
'value'
]
margin
=
input_options
[
'margin'
]
return
abs
(
submitted_value
-
expected_value
)
<=
margin
else
:
return
True
@staticmethod
def
workbench_scenarios
():
def
workbench_scenarios
():
"""
"""
A canned scenario for display in the workbench.
A canned scenario for display in the workbench.
...
...
drag_and_drop_v2/public/css/drag_and_drop.css
View file @
7fd8c2ed
...
@@ -193,49 +193,6 @@
...
@@ -193,49 +193,6 @@
max-width
:
100%
;
max-width
:
100%
;
}
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input
{
height
:
32px
;
position
:
absolute
;
left
:
calc
(
100%
+
5px
);
top
:
calc
(
50%
-
16px
);
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input
.spinner-wrapper
{
position
:
absolute
;
right
:
0
;
top
:
0
;
margin-right
:
5px
;
padding-top
:
6px
;
color
:
#333
;
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input
.input
{
display
:
inline-block
;
width
:
144px
;
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input
.submit-input
{
position
:
absolute
;
left
:
150px
;
top
:
4px
;
white-space
:
nowrap
;
/* Fix cross-browser issue: Without this declaration, button text wraps in Chrome/Chromium */
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input.correct
.input-submit
,
.xblock--drag-and-drop
.drag-container
.option
.numerical-input.incorrect
.input-submit
{
display
:
none
;
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input.correct
.input
{
background-color
:
#ceffce
;
color
:
#087108
;
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input.incorrect
.input
{
background-color
:
#ffcece
;
color
:
#ad0d0d
;
}
.xblock--drag-and-drop
.drag-container
.option.fade
{
.xblock--drag-and-drop
.drag-container
.option.fade
{
opacity
:
0.80
;
opacity
:
0.80
;
}
}
...
...
drag_and_drop_v2/public/css/drag_and_drop_edit.css
View file @
7fd8c2ed
...
@@ -196,12 +196,6 @@
...
@@ -196,12 +196,6 @@
width
:
50px
;
width
:
50px
;
}
}
.xblock--drag-and-drop--editor
.items-form
.item-numerical-value
,
.xblock--drag-and-drop--editor
.items-form
.item-numerical-margin
{
margin
:
0
1%
;
width
:
50%
;
}
.xblock--drag-and-drop--editor
.items-form
textarea
{
.xblock--drag-and-drop--editor
.items-form
textarea
{
width
:
97%
;
width
:
97%
;
margin
:
0
1%
;
margin
:
0
1%
;
...
...
drag_and_drop_v2/public/js/drag_and_drop.js
View file @
7fd8c2ed
...
@@ -4,20 +4,6 @@ function DragNDropTemplates(url_name) {
...
@@ -4,20 +4,6 @@ function DragNDropTemplates(url_name) {
// Set up a mock for gettext if it isn't available in the client runtime:
// Set up a mock for gettext if it isn't available in the client runtime:
if
(
!
window
.
gettext
)
{
window
.
gettext
=
function
gettext_stub
(
string
)
{
return
string
;
};
}
if
(
!
window
.
gettext
)
{
window
.
gettext
=
function
gettext_stub
(
string
)
{
return
string
;
};
}
var
FocusHook
=
function
()
{
if
(
!
(
this
instanceof
FocusHook
))
{
return
new
FocusHook
();
}
};
FocusHook
.
prototype
.
hook
=
function
(
node
,
prop
,
prev
)
{
setTimeout
(
function
()
{
if
(
document
.
activeElement
!==
node
)
{
node
.
focus
();
}
},
0
);
};
var
itemSpinnerTemplate
=
function
(
xhr_active
)
{
var
itemSpinnerTemplate
=
function
(
xhr_active
)
{
if
(
!
xhr_active
)
{
if
(
!
xhr_active
)
{
return
null
;
return
null
;
...
@@ -36,22 +22,6 @@ function DragNDropTemplates(url_name) {
...
@@ -36,22 +22,6 @@ function DragNDropTemplates(url_name) {
});
});
};
};
var
itemInputTemplate
=
function
(
input
)
{
if
(
!
input
)
{
return
null
;
}
var
focus_hook
=
input
.
has_value
?
undefined
:
FocusHook
();
return
(
h
(
'div.numerical-input'
,
{
className
:
input
.
class_name
,
style
:
{
display
:
input
.
is_visible
?
'block'
:
'none'
}},
[
h
(
'input.input'
,
{
type
:
'text'
,
value
:
input
.
value
,
disabled
:
input
.
has_value
,
focusHook
:
focus_hook
}),
itemSpinnerTemplate
(
input
.
xhr_active
),
h
(
'button.submit-input'
,
{
disabled
:
input
.
has_value
},
gettext
(
'ok'
))
])
);
};
var
getZone
=
function
(
zoneUID
,
ctx
)
{
var
getZone
=
function
(
zoneUID
,
ctx
)
{
for
(
var
i
=
0
;
i
<
ctx
.
zones
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
ctx
.
zones
.
length
;
i
++
)
{
if
(
ctx
.
zones
[
i
].
uid
===
zoneUID
)
{
if
(
ctx
.
zones
[
i
].
uid
===
zoneUID
)
{
...
@@ -98,10 +68,6 @@ function DragNDropTemplates(url_name) {
...
@@ -98,10 +68,6 @@ function DragNDropTemplates(url_name) {
}
}
}
else
{
}
else
{
// This is an "aligned" zone, so the item position within the zone is calculated by the browser.
// This is an "aligned" zone, so the item position within the zone is calculated by the browser.
// Allow for the input + button width for aligned items
if
(
item
.
input
)
{
style
.
marginRight
=
'190px'
;
}
// Make up for the fact we're in a wrapper container by calculating percentage differences.
// Make up for the fact we're in a wrapper container by calculating percentage differences.
var
maxWidth
=
(
item
.
widthPercent
||
30
)
/
100
;
var
maxWidth
=
(
item
.
widthPercent
||
30
)
/
100
;
var
widthPercent
=
zone
.
width_percent
/
100
;
var
widthPercent
=
zone
.
width_percent
/
100
;
...
@@ -132,8 +98,7 @@ function DragNDropTemplates(url_name) {
...
@@ -132,8 +98,7 @@ function DragNDropTemplates(url_name) {
}
}
// Define children
// Define children
var
children
=
[
var
children
=
[
itemSpinnerTemplate
(
item
.
xhr_active
),
itemSpinnerTemplate
(
item
.
xhr_active
)
itemInputTemplate
(
item
.
input
)
];
];
var
item_content_html
=
item
.
displayName
;
var
item_content_html
=
item
.
displayName
;
if
(
item
.
imageURL
)
{
if
(
item
.
imageURL
)
{
...
@@ -386,7 +351,6 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -386,7 +351,6 @@ function DragAndDropBlock(runtime, element, configuration) {
$element
.
on
(
'keydown'
,
'.reset-button'
,
function
(
evt
)
{
$element
.
on
(
'keydown'
,
'.reset-button'
,
function
(
evt
)
{
runOnKey
(
evt
,
RET
,
resetProblem
);
runOnKey
(
evt
,
RET
,
resetProblem
);
});
});
$element
.
on
(
'click'
,
'.submit-input'
,
submitInput
);
// For the next one, we need to use addEventListener with useCapture 'true' in order
// For the next one, we need to use addEventListener with useCapture 'true' in order
// to watch for load events on any child element, since load events do not bubble.
// to watch for load events on any child element, since load events do not bubble.
...
@@ -783,9 +747,9 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -783,9 +747,9 @@ function DragAndDropBlock(runtime, element, configuration) {
$
.
post
(
url
,
JSON
.
stringify
(
data
),
'json'
)
$
.
post
(
url
,
JSON
.
stringify
(
data
),
'json'
)
.
done
(
function
(
data
){
.
done
(
function
(
data
){
state
.
last_action_correct
=
data
.
correct
_location
;
state
.
last_action_correct
=
data
.
correct
;
if
(
data
.
correct
_location
)
{
if
(
data
.
correct
)
{
state
.
items
[
item_id
].
correct
_input
=
Boolean
(
data
.
correct
)
;
state
.
items
[
item_id
].
correct
=
true
;
state
.
items
[
item_id
].
submitting_location
=
false
;
state
.
items
[
item_id
].
submitting_location
=
false
;
}
else
{
}
else
{
delete
state
.
items
[
item_id
];
delete
state
.
items
[
item_id
];
...
@@ -803,42 +767,6 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -803,42 +767,6 @@ function DragAndDropBlock(runtime, element, configuration) {
});
});
};
};
var
submitInput
=
function
(
evt
)
{
var
item
=
$
(
evt
.
target
).
closest
(
'.option'
);
var
input_div
=
item
.
find
(
'.numerical-input'
);
var
input
=
input_div
.
find
(
'.input'
);
var
input_value
=
input
.
val
();
var
item_id
=
item
.
data
(
'value'
);
if
(
!
input_value
)
{
// Don't submit if the user didn't enter anything yet.
return
;
}
state
.
items
[
item_id
].
input
=
input_value
;
state
.
items
[
item_id
].
submitting_input
=
true
;
applyState
();
var
url
=
runtime
.
handlerUrl
(
element
,
'do_attempt'
);
var
data
=
{
val
:
item_id
,
input
:
input_value
};
$
.
post
(
url
,
JSON
.
stringify
(
data
),
'json'
)
.
done
(
function
(
data
)
{
state
.
last_action_correct
=
data
.
correct
;
state
.
items
[
item_id
].
submitting_input
=
false
;
state
.
items
[
item_id
].
correct_input
=
data
.
correct
;
state
.
feedback
=
data
.
feedback
;
if
(
data
.
finished
)
{
state
.
finished
=
true
;
state
.
overall_feedback
=
data
.
overall_feedback
;
}
applyState
();
})
.
fail
(
function
(
data
)
{
state
.
items
[
item_id
].
submitting_input
=
false
;
applyState
();
});
};
var
closePopup
=
function
(
evt
)
{
var
closePopup
=
function
(
evt
)
{
if
(
!
state
.
feedback
)
{
if
(
!
state
.
feedback
)
{
return
;
return
;
...
@@ -847,9 +775,8 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -847,9 +775,8 @@ function DragAndDropBlock(runtime, element, configuration) {
var
target
=
$
(
evt
.
target
);
var
target
=
$
(
evt
.
target
);
var
popup_box
=
'.xblock--drag-and-drop .popup'
;
var
popup_box
=
'.xblock--drag-and-drop .popup'
;
var
close_button
=
'.xblock--drag-and-drop .popup .close'
;
var
close_button
=
'.xblock--drag-and-drop .popup .close'
;
var
submit_input_button
=
'.xblock--drag-and-drop .submit-input'
;
if
(
target
.
is
(
popup_box
)
||
target
.
is
(
submit_input_button
)
)
{
if
(
target
.
is
(
popup_box
))
{
return
;
return
;
}
}
if
(
target
.
parents
(
popup_box
).
length
&&
!
target
.
is
(
close_button
))
{
if
(
target
.
parents
(
popup_box
).
length
&&
!
target
.
is
(
close_button
))
{
...
@@ -884,31 +811,17 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -884,31 +811,17 @@ function DragAndDropBlock(runtime, element, configuration) {
var
render
=
function
()
{
var
render
=
function
()
{
var
items
=
configuration
.
items
.
map
(
function
(
item
)
{
var
items
=
configuration
.
items
.
map
(
function
(
item
)
{
var
input
=
null
;
var
item_user_state
=
state
.
items
[
item
.
id
];
var
item_user_state
=
state
.
items
[
item
.
id
];
if
(
item
.
inputOptions
)
{
input
=
{
is_visible
:
item_user_state
&&
!
item_user_state
.
submitting_location
,
has_value
:
Boolean
(
item_user_state
&&
'input'
in
item_user_state
),
value
:
(
item_user_state
&&
item_user_state
.
input
)
||
''
,
class_name
:
undefined
,
xhr_active
:
(
item_user_state
&&
item_user_state
.
submitting_input
)
};
if
(
input
.
has_value
&&
!
item_user_state
.
submitting_input
)
{
input
.
class_name
=
item_user_state
.
correct_input
?
'correct'
:
'incorrect'
;
}
}
var
grabbed
=
false
;
var
grabbed
=
false
;
if
(
item
.
grabbed
!==
undefined
)
{
if
(
item
.
grabbed
!==
undefined
)
{
grabbed
=
item
.
grabbed
;
grabbed
=
item
.
grabbed
;
}
}
var
placed
=
item_user_state
&&
(
'input'
in
item_user_state
||
item_user_state
.
correct_input
)
;
var
placed
=
item_user_state
&&
item_user_state
.
correct
;
var
itemProperties
=
{
var
itemProperties
=
{
value
:
item
.
id
,
value
:
item
.
id
,
drag_disabled
:
Boolean
(
item_user_state
||
state
.
finished
),
drag_disabled
:
Boolean
(
item_user_state
||
state
.
finished
),
class_name
:
placed
||
state
.
finished
?
'fade'
:
undefined
,
class_name
:
placed
||
state
.
finished
?
'fade'
:
undefined
,
xhr_active
:
(
item_user_state
&&
item_user_state
.
submitting_location
),
xhr_active
:
(
item_user_state
&&
item_user_state
.
submitting_location
),
input
:
input
,
displayName
:
item
.
displayName
,
displayName
:
item
.
displayName
,
imageURL
:
item
.
expandedImageURL
,
imageURL
:
item
.
expandedImageURL
,
imageDescription
:
item
.
imageDescription
,
imageDescription
:
item
.
imageDescription
,
...
...
drag_and_drop_v2/public/js/drag_and_drop_edit.js
View file @
7fd8c2ed
...
@@ -414,10 +414,6 @@ function DragAndDropEditBlock(runtime, element, params) {
...
@@ -414,10 +414,6 @@ function DragAndDropEditBlock(runtime, element, params) {
// block, but preserve the data in case we need it again:
// block, but preserve the data in case we need it again:
ctx
.
pixelHeight
=
itemData
.
size
.
height
.
substr
(
0
,
itemData
.
size
.
height
.
length
-
2
);
// Remove 'px'
ctx
.
pixelHeight
=
itemData
.
size
.
height
.
substr
(
0
,
itemData
.
size
.
height
.
length
-
2
);
// Remove 'px'
}
}
if
(
itemData
.
inputOptions
)
{
ctx
.
numericalValue
=
itemData
.
inputOptions
.
value
;
ctx
.
numericalMargin
=
itemData
.
inputOptions
.
margin
;
}
}
}
ctx
.
dropdown
=
_fn
.
build
.
form
.
createDropdown
(
ctx
.
zone
);
ctx
.
dropdown
=
_fn
.
build
.
form
.
createDropdown
(
ctx
.
zone
);
...
@@ -486,15 +482,6 @@ function DragAndDropEditBlock(runtime, element, params) {
...
@@ -486,15 +482,6 @@ function DragAndDropEditBlock(runtime, element, params) {
var
widthPercent
=
$el
.
find
(
'.item-width'
).
val
();
var
widthPercent
=
$el
.
find
(
'.item-width'
).
val
();
if
(
widthPercent
&&
+
widthPercent
>
0
)
{
data
.
widthPercent
=
widthPercent
;
}
if
(
widthPercent
&&
+
widthPercent
>
0
)
{
data
.
widthPercent
=
widthPercent
;
}
var
numValue
=
parseFloat
(
$el
.
find
(
'.item-numerical-value'
).
val
());
var
numMargin
=
parseFloat
(
$el
.
find
(
'.item-numerical-margin'
).
val
());
if
(
isFinite
(
numValue
))
{
data
.
inputOptions
=
{
value
:
numValue
,
margin
:
isFinite
(
numMargin
)
?
numMargin
:
0
};
}
items
.
push
(
data
);
items
.
push
(
data
);
}
}
});
});
...
...
drag_and_drop_v2/public/themes/apros.css
View file @
7fd8c2ed
...
@@ -32,16 +32,6 @@
...
@@ -32,16 +32,6 @@
opacity
:
1
;
opacity
:
1
;
}
}
.themed-xblock.xblock--drag-and-drop
.drag-container
.option
.numerical-input.correct
.input
{
background-color
:
#ceffce
;
color
:
#087108
;
}
.themed-xblock.xblock--drag-and-drop
.drag-container
.option
.numerical-input.incorrect
.input
{
background-color
:
#ffcece
;
color
:
#ad0d0d
;
}
.themed-xblock.xblock--drag-and-drop
.drag-container
.option.fade
{
.themed-xblock.xblock--drag-and-drop
.drag-container
.option.fade
{
opacity
:
0.5
;
opacity
:
0.5
;
}
}
...
@@ -85,4 +75,4 @@
...
@@ -85,4 +75,4 @@
.themed-xblock.xblock--drag-and-drop
.link-button
{
.themed-xblock.xblock--drag-and-drop
.link-button
{
cursor
:
pointer
;
cursor
:
pointer
;
color
:
#3384ca
;
color
:
#3384ca
;
}
}
\ No newline at end of file
drag_and_drop_v2/templates/html/js_templates.html
View file @
7fd8c2ed
...
@@ -131,23 +131,5 @@
...
@@ -131,23 +131,5 @@
<
label
for
=
"item-{{id}}-width-percent"
>
{{
i18n
"Preferred width as a percentage of the background image width (or blank for automatic width):"
}}
<
/label
>
<
label
for
=
"item-{{id}}-width-percent"
>
{{
i18n
"Preferred width as a percentage of the background image width (or blank for automatic width):"
}}
<
/label
>
<
input
type
=
"number"
id
=
"item-{{id}}-width-percent"
class
=
"item-width"
value
=
"{{ singleDecimalFloat widthPercent }}"
step
=
"0.1"
min
=
"1"
max
=
"99"
/>%
<
input
type
=
"number"
id
=
"item-{{id}}-width-percent"
class
=
"item-width"
value
=
"{{ singleDecimalFloat widthPercent }}"
step
=
"0.1"
min
=
"1"
max
=
"99"
/>%
<
/div
>
<
/div
>
<
div
class
=
"row advanced"
>
<
label
for
=
"item-{{id}}-numerical-value"
>
{{
i18n
"Optional numerical value (if you set this, learners will be prompted for this value after dropping this item)"
}}
<
/label
>
<
input
type
=
"number"
step
=
"0.1"
id
=
"item-{{id}}-numerical-value"
class
=
"item-numerical-value"
value
=
"{{ numericalValue }}"
/>
<
/div
>
<
div
class
=
"row advanced"
>
<
label
for
=
"item-{{id}}-numerical-margin"
>
{{
i18n
"Margin ± (when a numerical value is required, values entered by learners must not differ from the expected value by more than this margin; default is zero)"
}}
<
/label
>
<
input
type
=
"number"
step
=
"0.1"
id
=
"item-{{id}}-numerical-margin"
class
=
"item-numerical-margin"
value
=
"{{ numericalMargin }}"
/>
<
/div
>
<
/div
>
<
/div
>
</script>
</script>
drag_and_drop_v2/translations/en/LC_MESSAGES/text.po
View file @
7fd8c2ed
...
@@ -248,19 +248,6 @@ msgid ""
...
@@ -248,19 +248,6 @@ msgid ""
"automatic width):"
"automatic width):"
msgstr ""
msgstr ""
#: templates/html/js_templates.html
msgid ""
"Optional numerical value (if you set this, learners will be prompted for "
"this value after dropping this item)"
msgstr ""
#: templates/html/js_templates.html
msgid ""
"Margin ± (when a numerical value is required, values entered by learners "
"must not differ from the expected value by more than this margin; default "
"is zero)"
msgstr ""
#: templates/html/drag_and_drop.html
#: templates/html/drag_and_drop.html
msgid "Loading drag and drop problem."
msgid "Loading drag and drop problem."
msgstr ""
msgstr ""
...
...
drag_and_drop_v2/translations/eo/LC_MESSAGES/text.po
View file @
7fd8c2ed
...
@@ -304,29 +304,6 @@ msgstr ""
...
@@ -304,29 +304,6 @@ msgstr ""
"Préférréd wïdth äs ä pérçéntägé öf thé ßäçkgröünd ïmägé wïdth (ör ßlänk för "
"Préférréd wïdth äs ä pérçéntägé öf thé ßäçkgröünd ïmägé wïdth (ör ßlänk för "
"äütömätïç wïdth): Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#"
"äütömätïç wïdth): Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#"
#: templates/html/js_templates.html
msgid ""
"Optional numerical value (if you set this, learners will be prompted for "
"this value after dropping this item)"
msgstr ""
"Öptïönäl nümérïçäl välüé (ïf ýöü sét thïs, léärnérs wïll ßé prömptéd för "
"thïs välüé äftér dröppïng thïs ïtém) Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
#: templates/html/js_templates.html
msgid ""
"Margin ± (when a numerical value is required, values entered by learners "
"must not differ from the expected value by more than this margin; default is"
" zero)"
msgstr ""
"Märgïn ± (whén ä nümérïçäl välüé ïs réqüïréd, välüés éntéréd ßý léärnérs "
"müst nöt dïffér fröm thé éxpéçtéd välüé ßý möré thän thïs märgïn; défäült ïs"
" zérö) Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ "
"єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм"
" νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα "
"¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт"
" єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт "
"¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσ#"
#: templates/html/drag_and_drop.html
#: templates/html/drag_and_drop.html
msgid "Loading drag and drop problem."
msgid "Loading drag and drop problem."
msgstr "Löädïng dräg änd dröp prößlém. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
msgstr "Löädïng dräg änd dröp prößlém. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
...
...
tests/integration/data/old_version_data.json
View file @
7fd8c2ed
...
@@ -47,10 +47,6 @@
...
@@ -47,10 +47,6 @@
"size"
:
{
"size"
:
{
"width"
:
"190px"
,
"width"
:
"190px"
,
"height"
:
"100px"
"height"
:
"100px"
},
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
}
},
},
{
{
...
@@ -77,4 +73,4 @@
...
@@ -77,4 +73,4 @@
"finish"
:
"Final Feedback"
"finish"
:
"Final Feedback"
},
},
"title"
:
"Drag and Drop (Old-style data)"
"title"
:
"Drag and Drop (Old-style data)"
}
}
\ No newline at end of file
tests/integration/data/test_data.json
View file @
7fd8c2ed
...
@@ -36,11 +36,7 @@
...
@@ -36,11 +36,7 @@
},
},
"zone"
:
"zone-2"
,
"zone"
:
"zone-2"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"id"
:
1
,
"id"
:
1
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
},
},
{
{
"displayName"
:
"X"
,
"displayName"
:
"X"
,
...
...
tests/integration/data/test_data_other.json
View file @
7fd8c2ed
...
@@ -36,11 +36,7 @@
...
@@ -36,11 +36,7 @@
},
},
"zone"
:
"zone-52"
,
"zone"
:
"zone-52"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"id"
:
20
,
"id"
:
20
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
},
},
{
{
"displayName"
:
"X"
,
"displayName"
:
"X"
,
...
...
tests/integration/data/test_html_data.json
View file @
7fd8c2ed
...
@@ -36,11 +36,7 @@
...
@@ -36,11 +36,7 @@
},
},
"zone"
:
"zone-2"
,
"zone"
:
"zone-2"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"id"
:
1
,
"id"
:
1
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
},
},
{
{
"displayName"
:
"<span style='color:red'>X</span>"
,
"displayName"
:
"<span style='color:red'>X</span>"
,
...
...
tests/integration/test_custom_data_render.py
View file @
7fd8c2ed
...
@@ -22,7 +22,6 @@ class TestCustomDataDragAndDropRendering(BaseIntegrationTest):
...
@@ -22,7 +22,6 @@ class TestCustomDataDragAndDropRendering(BaseIntegrationTest):
self
.
assertEqual
(
len
(
items
),
3
)
self
.
assertEqual
(
len
(
items
),
3
)
self
.
assertIn
(
'<b>1</b>'
,
self
.
get_element_html
(
items
[
0
]))
self
.
assertIn
(
'<b>1</b>'
,
self
.
get_element_html
(
items
[
0
]))
self
.
assertIn
(
'<i>2</i>'
,
self
.
get_element_html
(
items
[
1
]))
self
.
assertIn
(
'<i>2</i>'
,
self
.
get_element_html
(
items
[
1
]))
self
.
assertIn
(
'<input class="input" type="text">'
,
self
.
get_element_html
(
items
[
1
]))
self
.
assertIn
(
'<span style="color:red">X</span>'
,
self
.
get_element_html
(
items
[
2
]))
self
.
assertIn
(
'<span style="color:red">X</span>'
,
self
.
get_element_html
(
items
[
2
]))
def
test_background_image
(
self
):
def
test_background_image
(
self
):
...
...
tests/integration/test_interaction.py
View file @
7fd8c2ed
...
@@ -27,13 +27,12 @@ loader = ResourceLoader(__name__)
...
@@ -27,13 +27,12 @@ loader = ResourceLoader(__name__)
# Classes ###########################################################
# Classes ###########################################################
class
ItemDefinition
(
object
):
class
ItemDefinition
(
object
):
def
__init__
(
self
,
item_id
,
zone_id
,
zone_title
,
feedback_positive
,
feedback_negative
,
input_value
=
None
):
def
__init__
(
self
,
item_id
,
zone_id
,
zone_title
,
feedback_positive
,
feedback_negative
):
self
.
feedback_negative
=
feedback_negative
self
.
feedback_negative
=
feedback_negative
self
.
feedback_positive
=
feedback_positive
self
.
feedback_positive
=
feedback_positive
self
.
zone_id
=
zone_id
self
.
zone_id
=
zone_id
self
.
zone_title
=
zone_title
self
.
zone_title
=
zone_title
self
.
item_id
=
item_id
self
.
item_id
=
item_id
self
.
input
=
input_value
class
InteractionTestBase
(
object
):
class
InteractionTestBase
(
object
):
...
@@ -77,10 +76,6 @@ class InteractionTestBase(object):
...
@@ -77,10 +76,6 @@ class InteractionTestBase(object):
zones_container
=
self
.
_page
.
find_element_by_css_selector
(
'.target'
)
zones_container
=
self
.
_page
.
find_element_by_css_selector
(
'.target'
)
return
zones_container
.
find_elements_by_xpath
(
".//div[@data-uid='{zone_id}']"
.
format
(
zone_id
=
zone_id
))[
0
]
return
zones_container
.
find_elements_by_xpath
(
".//div[@data-uid='{zone_id}']"
.
format
(
zone_id
=
zone_id
))[
0
]
def
_get_input_div_by_value
(
self
,
item_value
):
element
=
self
.
_get_item_by_value
(
item_value
)
return
element
.
find_element_by_class_name
(
'numerical-input'
)
def
_get_dialog_components
(
self
,
dialog
):
# pylint: disable=no-self-use
def
_get_dialog_components
(
self
,
dialog
):
# pylint: disable=no-self-use
dialog_modal_overlay
=
dialog
.
find_element_by_css_selector
(
'.modal-window-overlay'
)
dialog_modal_overlay
=
dialog
.
find_element_by_css_selector
(
'.modal-window-overlay'
)
dialog_modal
=
dialog
.
find_element_by_css_selector
(
'.modal-window'
)
dialog_modal
=
dialog
.
find_element_by_css_selector
(
'.modal-window'
)
...
@@ -119,17 +114,6 @@ class InteractionTestBase(object):
...
@@ -119,17 +114,6 @@ class InteractionTestBase(object):
self
.
_page
.
send_keys
(
Keys
.
TAB
)
self
.
_page
.
send_keys
(
Keys
.
TAB
)
self
.
_get_zone_by_id
(
zone_id
)
.
send_keys
(
action_key
)
self
.
_get_zone_by_id
(
zone_id
)
.
send_keys
(
action_key
)
def
send_input
(
self
,
item_value
,
value
):
element
=
self
.
_get_item_by_value
(
item_value
)
self
.
wait_until_visible
(
element
)
# Since virtual-dom may be updating DOM elements by replacing them completely, the
# following method must be used to wait for the input box to appear:
textbox_visible_selector
=
'.numerical-input[style*="display: block"] input'
self
.
wait_until_exists
(
textbox_visible_selector
)
textbox
=
self
.
_page
.
find_element_by_css_selector
(
textbox_visible_selector
)
textbox
.
send_keys
(
value
)
element
.
find_element_by_class_name
(
'submit-input'
)
.
click
()
def
assert_grabbed_item
(
self
,
item
):
def
assert_grabbed_item
(
self
,
item
):
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'true'
)
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'true'
)
...
@@ -185,28 +169,10 @@ class InteractionTestBase(object):
...
@@ -185,28 +169,10 @@ class InteractionTestBase(object):
self
.
scroll_down
(
pixels
=
scroll_down
)
self
.
scroll_down
(
pixels
=
scroll_down
)
for
definition
in
self
.
_get_items_with_zone
(
items_map
)
.
values
():
for
definition
in
self
.
_get_items_with_zone
(
items_map
)
.
values
():
if
not
definition
.
input
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup_content
)
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup_content
)
self
.
assertEqual
(
popup
.
get_attribute
(
'class'
),
'popup'
)
self
.
assertEqual
(
popup
.
get_attribute
(
'class'
),
'popup'
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_title
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_title
)
def
parameterized_item_positive_feedback_on_good_input
(
self
,
items_map
,
scroll_down
=
100
,
action_key
=
None
):
popup
=
self
.
_get_popup
()
feedback_popup_content
=
self
.
_get_popup_content
()
# Scroll drop zones into view to make sure Selenium can successfully drop items
self
.
scroll_down
(
pixels
=
scroll_down
)
for
definition
in
self
.
_get_items_with_zone
(
items_map
)
.
values
():
if
definition
.
input
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
send_input
(
definition
.
item_id
,
definition
.
input
)
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup_content
)
self
.
assertEqual
(
popup
.
get_attribute
(
'class'
),
'popup'
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_title
)
input_div
=
self
.
_get_input_div_by_value
(
definition
.
item_id
)
self
.
wait_until_has_class
(
'correct'
,
input_div
)
def
parameterized_item_negative_feedback_on_bad_move
(
self
,
items_map
,
all_zones
,
scroll_down
=
100
,
action_key
=
None
):
def
parameterized_item_negative_feedback_on_bad_move
(
self
,
items_map
,
all_zones
,
scroll_down
=
100
,
action_key
=
None
):
popup
=
self
.
_get_popup
()
popup
=
self
.
_get_popup
()
...
@@ -224,23 +190,6 @@ class InteractionTestBase(object):
...
@@ -224,23 +190,6 @@ class InteractionTestBase(object):
self
.
assertEqual
(
popup
.
get_attribute
(
'class'
),
'popup popup-incorrect'
)
self
.
assertEqual
(
popup
.
get_attribute
(
'class'
),
'popup popup-incorrect'
)
self
.
assert_reverted_item
(
definition
.
item_id
)
self
.
assert_reverted_item
(
definition
.
item_id
)
def
parameterized_item_negative_feedback_on_bad_input
(
self
,
items_map
,
scroll_down
=
100
,
action_key
=
None
):
popup
=
self
.
_get_popup
()
feedback_popup_content
=
self
.
_get_popup_content
()
# Scroll drop zones into view to make sure Selenium can successfully drop items
self
.
scroll_down
(
pixels
=
scroll_down
)
for
definition
in
self
.
_get_items_with_zone
(
items_map
)
.
values
():
if
definition
.
input
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
send_input
(
definition
.
item_id
,
'1999999'
)
self
.
wait_until_html_in
(
definition
.
feedback_negative
,
feedback_popup_content
)
self
.
assertEqual
(
popup
.
get_attribute
(
'class'
),
'popup popup-incorrect'
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_title
)
input_div
=
self
.
_get_input_div_by_value
(
definition
.
item_id
)
self
.
wait_until_has_class
(
'incorrect'
,
input_div
)
def
parameterized_final_feedback_and_reset
(
self
,
items_map
,
feedback
,
scroll_down
=
100
,
action_key
=
None
):
def
parameterized_final_feedback_and_reset
(
self
,
items_map
,
feedback
,
scroll_down
=
100
,
action_key
=
None
):
feedback_message
=
self
.
_get_feedback_message
()
feedback_message
=
self
.
_get_feedback_message
()
self
.
assertEqual
(
self
.
get_element_html
(
feedback_message
),
feedback
[
'intro'
])
# precondition check
self
.
assertEqual
(
self
.
get_element_html
(
feedback_message
),
feedback
[
'intro'
])
# precondition check
...
@@ -257,10 +206,6 @@ class InteractionTestBase(object):
...
@@ -257,10 +206,6 @@ class InteractionTestBase(object):
for
item_key
,
definition
in
items
.
items
():
for
item_key
,
definition
in
items
.
items
():
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
if
definition
.
input
:
self
.
send_input
(
item_key
,
definition
.
input
)
input_div
=
self
.
_get_input_div_by_value
(
item_key
)
self
.
wait_until_has_class
(
'correct'
,
input_div
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_title
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_title
)
self
.
wait_until_html_in
(
feedback
[
'final'
],
self
.
_get_feedback_message
())
self
.
wait_until_html_in
(
feedback
[
'final'
],
self
.
_get_feedback_message
())
...
@@ -367,15 +312,9 @@ class BasicInteractionTest(DefaultDataTestMixin, InteractionTestBase):
...
@@ -367,15 +312,9 @@ class BasicInteractionTest(DefaultDataTestMixin, InteractionTestBase):
def
test_item_positive_feedback_on_good_move
(
self
):
def
test_item_positive_feedback_on_good_move
(
self
):
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
)
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
)
def
test_item_positive_feedback_on_good_input
(
self
):
self
.
parameterized_item_positive_feedback_on_good_input
(
self
.
items_map
)
def
test_item_negative_feedback_on_bad_move
(
self
):
def
test_item_negative_feedback_on_bad_move
(
self
):
self
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
items_map
,
self
.
all_zones
)
self
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
items_map
,
self
.
all_zones
)
def
test_item_negative_feedback_on_bad_input
(
self
):
self
.
parameterized_item_negative_feedback_on_bad_input
(
self
.
items_map
)
def
test_final_feedback_and_reset
(
self
):
def
test_final_feedback_and_reset
(
self
):
self
.
parameterized_final_feedback_and_reset
(
self
.
items_map
,
self
.
feedback
)
self
.
parameterized_final_feedback_and_reset
(
self
.
items_map
,
self
.
feedback
)
...
@@ -405,9 +344,7 @@ class EventsFiredTest(DefaultDataTestMixin, InteractionTestBase, BaseIntegration
...
@@ -405,9 +344,7 @@ class EventsFiredTest(DefaultDataTestMixin, InteractionTestBase, BaseIntegration
{
{
'name'
:
'edx.drag_and_drop_v2.item.dropped'
,
'name'
:
'edx.drag_and_drop_v2.item.dropped'
,
'data'
:
{
'data'
:
{
'input'
:
None
,
'is_correct'
:
True
,
'is_correct'
:
True
,
'is_correct_location'
:
True
,
'item_id'
:
0
,
'item_id'
:
0
,
'location'
:
TOP_ZONE_TITLE
,
'location'
:
TOP_ZONE_TITLE
,
'location_id'
:
TOP_ZONE_ID
,
'location_id'
:
TOP_ZONE_ID
,
...
@@ -459,18 +396,10 @@ class KeyboardInteractionTest(BasicInteractionTest, BaseIntegrationTest):
...
@@ -459,18 +396,10 @@ class KeyboardInteractionTest(BasicInteractionTest, BaseIntegrationTest):
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
,
action_key
=
action_key
)
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_positive_feedback_on_good_input_with_keyboard
(
self
,
action_key
):
self
.
parameterized_item_positive_feedback_on_good_input
(
self
.
items_map
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_negative_feedback_on_bad_move_with_keyboard
(
self
,
action_key
):
def
test_item_negative_feedback_on_bad_move_with_keyboard
(
self
,
action_key
):
self
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
items_map
,
self
.
all_zones
,
action_key
=
action_key
)
self
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
items_map
,
self
.
all_zones
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_negative_feedback_on_bad_input_with_keyboard
(
self
,
action_key
):
self
.
parameterized_item_negative_feedback_on_bad_input
(
self
.
items_map
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_final_feedback_and_reset_with_keyboard
(
self
,
action_key
):
def
test_final_feedback_and_reset_with_keyboard
(
self
,
action_key
):
self
.
parameterized_final_feedback_and_reset
(
self
.
items_map
,
self
.
feedback
,
action_key
=
action_key
)
self
.
parameterized_final_feedback_and_reset
(
self
.
items_map
,
self
.
feedback
,
action_key
=
action_key
)
...
@@ -481,7 +410,7 @@ class KeyboardInteractionTest(BasicInteractionTest, BaseIntegrationTest):
...
@@ -481,7 +410,7 @@ class KeyboardInteractionTest(BasicInteractionTest, BaseIntegrationTest):
class
CustomDataInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
class
CustomDataInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
items_map
=
{
items_map
=
{
0
:
ItemDefinition
(
0
,
'zone-1'
,
"Zone 1"
,
"Yes 1"
,
"No 1"
),
0
:
ItemDefinition
(
0
,
'zone-1'
,
"Zone 1"
,
"Yes 1"
,
"No 1"
),
1
:
ItemDefinition
(
1
,
'zone-2'
,
"Zone 2"
,
"Yes 2"
,
"No 2"
,
"102"
),
1
:
ItemDefinition
(
1
,
'zone-2'
,
"Zone 2"
,
"Yes 2"
,
"No 2"
),
2
:
ItemDefinition
(
2
,
None
,
None
,
""
,
"No Zone for this"
)
2
:
ItemDefinition
(
2
,
None
,
None
,
""
,
"No Zone for this"
)
}
}
...
@@ -499,7 +428,7 @@ class CustomDataInteractionTest(BasicInteractionTest, BaseIntegrationTest):
...
@@ -499,7 +428,7 @@ class CustomDataInteractionTest(BasicInteractionTest, BaseIntegrationTest):
class
CustomHtmlDataInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
class
CustomHtmlDataInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
items_map
=
{
items_map
=
{
0
:
ItemDefinition
(
0
,
'zone-1'
,
'Zone <i>1</i>'
,
"Yes <b>1</b>"
,
"No <b>1</b>"
),
0
:
ItemDefinition
(
0
,
'zone-1'
,
'Zone <i>1</i>'
,
"Yes <b>1</b>"
,
"No <b>1</b>"
),
1
:
ItemDefinition
(
1
,
'zone-2'
,
'Zone <b>2</b>'
,
"Yes <i>2</i>"
,
"No <i>2</i>"
,
"95"
),
1
:
ItemDefinition
(
1
,
'zone-2'
,
'Zone <b>2</b>'
,
"Yes <i>2</i>"
,
"No <i>2</i>"
),
2
:
ItemDefinition
(
2
,
None
,
None
,
""
,
"No Zone for <i>X</i>"
)
2
:
ItemDefinition
(
2
,
None
,
None
,
""
,
"No Zone for <i>X</i>"
)
}
}
...
@@ -524,12 +453,12 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
...
@@ -524,12 +453,12 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
item_maps
=
{
item_maps
=
{
'block1'
:
{
'block1'
:
{
0
:
ItemDefinition
(
0
,
'zone-1'
,
'Zone 1'
,
"Yes 1"
,
"No 1"
),
0
:
ItemDefinition
(
0
,
'zone-1'
,
'Zone 1'
,
"Yes 1"
,
"No 1"
),
1
:
ItemDefinition
(
1
,
'zone-2'
,
'Zone 2'
,
"Yes 2"
,
"No 2"
,
"102"
),
1
:
ItemDefinition
(
1
,
'zone-2'
,
'Zone 2'
,
"Yes 2"
,
"No 2"
),
2
:
ItemDefinition
(
2
,
None
,
None
,
""
,
"No Zone for this"
)
2
:
ItemDefinition
(
2
,
None
,
None
,
""
,
"No Zone for this"
)
},
},
'block2'
:
{
'block2'
:
{
10
:
ItemDefinition
(
10
,
'zone-51'
,
'Zone 51'
,
"Correct 1"
,
"Incorrect 1"
),
10
:
ItemDefinition
(
10
,
'zone-51'
,
'Zone 51'
,
"Correct 1"
,
"Incorrect 1"
),
20
:
ItemDefinition
(
20
,
'zone-52'
,
'Zone 52'
,
"Correct 2"
,
"Incorrect 2"
,
"102"
),
20
:
ItemDefinition
(
20
,
'zone-52'
,
'Zone 52'
,
"Correct 2"
,
"Incorrect 2"
),
30
:
ItemDefinition
(
30
,
None
,
None
,
""
,
"No Zone for this"
)
30
:
ItemDefinition
(
30
,
None
,
None
,
""
,
"No Zone for this"
)
},
},
}
}
...
@@ -558,12 +487,6 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
...
@@ -558,12 +487,6 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
self
.
_switch_to_block
(
1
)
self
.
_switch_to_block
(
1
)
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
item_maps
[
'block2'
],
scroll_down
=
900
)
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
item_maps
[
'block2'
],
scroll_down
=
900
)
def
test_item_positive_feedback_on_good_input
(
self
):
self
.
_switch_to_block
(
0
)
self
.
parameterized_item_positive_feedback_on_good_input
(
self
.
item_maps
[
'block1'
])
self
.
_switch_to_block
(
1
)
self
.
parameterized_item_positive_feedback_on_good_input
(
self
.
item_maps
[
'block2'
],
scroll_down
=
900
)
def
test_item_negative_feedback_on_bad_move
(
self
):
def
test_item_negative_feedback_on_bad_move
(
self
):
self
.
_switch_to_block
(
0
)
self
.
_switch_to_block
(
0
)
self
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
item_maps
[
'block1'
],
self
.
all_zones
[
'block1'
])
self
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
item_maps
[
'block1'
],
self
.
all_zones
[
'block1'
])
...
@@ -572,12 +495,6 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
...
@@ -572,12 +495,6 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
self
.
item_maps
[
'block2'
],
self
.
all_zones
[
'block2'
],
scroll_down
=
900
self
.
item_maps
[
'block2'
],
self
.
all_zones
[
'block2'
],
scroll_down
=
900
)
)
def
test_item_negative_feedback_on_bad_input
(
self
):
self
.
_switch_to_block
(
0
)
self
.
parameterized_item_negative_feedback_on_bad_input
(
self
.
item_maps
[
'block1'
])
self
.
_switch_to_block
(
1
)
self
.
parameterized_item_negative_feedback_on_bad_input
(
self
.
item_maps
[
'block2'
],
scroll_down
=
900
)
def
test_final_feedback_and_reset
(
self
):
def
test_final_feedback_and_reset
(
self
):
self
.
_switch_to_block
(
0
)
self
.
_switch_to_block
(
0
)
self
.
parameterized_final_feedback_and_reset
(
self
.
item_maps
[
'block1'
],
self
.
feedback
[
'block1'
])
self
.
parameterized_final_feedback_and_reset
(
self
.
item_maps
[
'block1'
],
self
.
feedback
[
'block1'
])
...
...
tests/unit/data/html/config_out.json
View file @
7fd8c2ed
...
@@ -36,29 +36,25 @@
...
@@ -36,29 +36,25 @@
"displayName"
:
"<b>1</b>"
,
"displayName"
:
"<b>1</b>"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
0
,
"id"
:
0
"inputOptions"
:
false
},
},
{
{
"displayName"
:
"<i>2</i>"
,
"displayName"
:
"<i>2</i>"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
1
,
"id"
:
1
"inputOptions"
:
true
},
},
{
{
"displayName"
:
"X"
,
"displayName"
:
"X"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
2
,
"id"
:
2
"inputOptions"
:
false
},
},
{
{
"displayName"
:
""
,
"displayName"
:
""
,
"imageURL"
:
"http://placehold.it/100x300"
,
"imageURL"
:
"http://placehold.it/100x300"
,
"expandedImageURL"
:
"http://placehold.it/100x300"
,
"expandedImageURL"
:
"http://placehold.it/100x300"
,
"id"
:
3
,
"id"
:
3
"inputOptions"
:
false
}
}
]
]
}
}
tests/unit/data/html/data.json
View file @
7fd8c2ed
...
@@ -39,11 +39,7 @@
...
@@ -39,11 +39,7 @@
},
},
"zone"
:
"Zone <b>2</b>"
,
"zone"
:
"Zone <b>2</b>"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"id"
:
1
,
"id"
:
1
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
},
},
{
{
"displayName"
:
"X"
,
"displayName"
:
"X"
,
...
...
tests/unit/data/old/config_out.json
View file @
7fd8c2ed
...
@@ -37,7 +37,6 @@
...
@@ -37,7 +37,6 @@
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
0
,
"id"
:
0
,
"inputOptions"
:
false
,
"size"
:
{
"height"
:
"auto"
,
"width"
:
"190px"
}
"size"
:
{
"height"
:
"auto"
,
"width"
:
"190px"
}
},
},
{
{
...
@@ -45,7 +44,6 @@
...
@@ -45,7 +44,6 @@
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
1
,
"id"
:
1
,
"inputOptions"
:
true
,
"size"
:
{
"height"
:
"auto"
,
"width"
:
"190px"
}
"size"
:
{
"height"
:
"auto"
,
"width"
:
"190px"
}
},
},
{
{
...
@@ -53,7 +51,6 @@
...
@@ -53,7 +51,6 @@
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
2
,
"id"
:
2
,
"inputOptions"
:
false
,
"size"
:
{
"height"
:
"100px"
,
"width"
:
"100px"
}
"size"
:
{
"height"
:
"100px"
,
"width"
:
"100px"
}
},
},
{
{
...
@@ -61,7 +58,6 @@
...
@@ -61,7 +58,6 @@
"imageURL"
:
"http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg"
,
"imageURL"
:
"http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg"
,
"expandedImageURL"
:
"http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg"
,
"expandedImageURL"
:
"http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg"
,
"id"
:
3
,
"id"
:
3
,
"inputOptions"
:
false
,
"size"
:
{
"height"
:
"auto"
,
"width"
:
"190px"
}
"size"
:
{
"height"
:
"auto"
,
"width"
:
"190px"
}
}
}
]
]
...
...
tests/unit/data/old/data.json
View file @
7fd8c2ed
...
@@ -46,10 +46,6 @@
...
@@ -46,10 +46,6 @@
"size"
:
{
"size"
:
{
"width"
:
"190px"
,
"width"
:
"190px"
,
"height"
:
"auto"
"height"
:
"auto"
},
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
}
},
},
{
{
...
...
tests/unit/data/plain/config_out.json
View file @
7fd8c2ed
...
@@ -36,29 +36,25 @@
...
@@ -36,29 +36,25 @@
"displayName"
:
"1"
,
"displayName"
:
"1"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
0
,
"id"
:
0
"inputOptions"
:
false
},
},
{
{
"displayName"
:
"2"
,
"displayName"
:
"2"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"expandedImageURL"
:
""
,
"id"
:
1
,
"id"
:
1
"inputOptions"
:
true
},
},
{
{
"displayName"
:
"X"
,
"displayName"
:
"X"
,
"imageURL"
:
"/static/test_url_expansion"
,
"imageURL"
:
"/static/test_url_expansion"
,
"expandedImageURL"
:
"/course/test-course/assets/test_url_expansion"
,
"expandedImageURL"
:
"/course/test-course/assets/test_url_expansion"
,
"id"
:
2
,
"id"
:
2
"inputOptions"
:
false
},
},
{
{
"displayName"
:
""
,
"displayName"
:
""
,
"imageURL"
:
"http://placehold.it/200x100"
,
"imageURL"
:
"http://placehold.it/200x100"
,
"expandedImageURL"
:
"http://placehold.it/200x100"
,
"expandedImageURL"
:
"http://placehold.it/200x100"
,
"id"
:
3
,
"id"
:
3
"inputOptions"
:
false
}
}
]
]
}
}
tests/unit/data/plain/data.json
View file @
7fd8c2ed
...
@@ -38,11 +38,7 @@
...
@@ -38,11 +38,7 @@
},
},
"zone"
:
"zone-2"
,
"zone"
:
"zone-2"
,
"imageURL"
:
""
,
"imageURL"
:
""
,
"id"
:
1
,
"id"
:
1
"inputOptions"
:
{
"value"
:
100
,
"margin"
:
5
}
},
},
{
{
"displayName"
:
"X"
,
"displayName"
:
"X"
,
...
...
tests/unit/test_advanced.py
View file @
7fd8c2ed
...
@@ -65,7 +65,6 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
...
@@ -65,7 +65,6 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
"overall_feedback"
:
None
,
"overall_feedback"
:
None
,
"finished"
:
False
,
"finished"
:
False
,
"correct"
:
False
,
"correct"
:
False
,
"correct_location"
:
False
,
"feedback"
:
self
.
FEEDBACK
[
item_id
][
"incorrect"
]
"feedback"
:
self
.
FEEDBACK
[
item_id
][
"incorrect"
]
})
})
...
@@ -77,7 +76,6 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
...
@@ -77,7 +76,6 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
"overall_feedback"
:
None
,
"overall_feedback"
:
None
,
"finished"
:
False
,
"finished"
:
False
,
"correct"
:
False
,
"correct"
:
False
,
"correct_location"
:
False
,
"feedback"
:
self
.
FEEDBACK
[
item_id
][
"incorrect"
]
"feedback"
:
self
.
FEEDBACK
[
item_id
][
"incorrect"
]
})
})
...
@@ -89,79 +87,9 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
...
@@ -89,79 +87,9 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
"overall_feedback"
:
None
,
"overall_feedback"
:
None
,
"finished"
:
False
,
"finished"
:
False
,
"correct"
:
True
,
"correct"
:
True
,
"correct_location"
:
True
,
"feedback"
:
self
.
FEEDBACK
[
item_id
][
"correct"
]
"feedback"
:
self
.
FEEDBACK
[
item_id
][
"correct"
]
})
})
def
test_do_attempt_with_input
(
self
):
# Drop item that requires numerical input
data
=
{
"val"
:
1
,
"zone"
:
self
.
ZONE_2
,
"x_percent"
:
"0
%
"
,
"y_percent"
:
"85
%
"
}
res
=
self
.
call_handler
(
'do_attempt'
,
data
)
self
.
assertEqual
(
res
,
{
"finished"
:
False
,
"correct"
:
False
,
"correct_location"
:
True
,
"feedback"
:
None
,
"overall_feedback"
:
None
,
})
expected_state
=
{
'items'
:
{
"1"
:
{
"x_percent"
:
"0
%
"
,
"y_percent"
:
"85
%
"
,
"correct_input"
:
False
,
"zone"
:
self
.
ZONE_2
,
},
},
'finished'
:
False
,
'overall_feedback'
:
self
.
initial_feedback
(),
}
self
.
assertEqual
(
expected_state
,
self
.
call_handler
(
'get_user_state'
,
method
=
"GET"
))
# Submit incorrect value
data
=
{
"val"
:
1
,
"input"
:
"250"
}
res
=
self
.
call_handler
(
'do_attempt'
,
data
)
self
.
assertEqual
(
res
,
{
"finished"
:
False
,
"correct"
:
False
,
"correct_location"
:
True
,
"feedback"
:
self
.
FEEDBACK
[
1
][
'incorrect'
],
"overall_feedback"
:
None
})
expected_state
=
{
'items'
:
{
"1"
:
{
"x_percent"
:
"0
%
"
,
"y_percent"
:
"85
%
"
,
"correct_input"
:
False
,
"zone"
:
self
.
ZONE_2
,
"input"
:
"250"
,
},
},
'finished'
:
False
,
'overall_feedback'
:
self
.
initial_feedback
(),
}
self
.
assertEqual
(
expected_state
,
self
.
call_handler
(
'get_user_state'
,
method
=
"GET"
))
# Submit correct value
data
=
{
"val"
:
1
,
"input"
:
"103"
}
res
=
self
.
call_handler
(
'do_attempt'
,
data
)
self
.
assertEqual
(
res
,
{
"finished"
:
False
,
"correct"
:
True
,
"correct_location"
:
True
,
"feedback"
:
self
.
FEEDBACK
[
1
][
'correct'
],
"overall_feedback"
:
None
,
})
expected_state
=
{
'items'
:
{
"1"
:
{
"x_percent"
:
"0
%
"
,
"y_percent"
:
"85
%
"
,
"correct_input"
:
True
,
"zone"
:
self
.
ZONE_2
,
"input"
:
"103"
,
},
},
'finished'
:
False
,
'overall_feedback'
:
self
.
initial_feedback
(),
}
self
.
assertEqual
(
expected_state
,
self
.
call_handler
(
'get_user_state'
,
method
=
"GET"
))
def
test_grading
(
self
):
def
test_grading
(
self
):
published_grades
=
[]
published_grades
=
[]
...
@@ -182,11 +110,6 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
...
@@ -182,11 +110,6 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
})
})
self
.
assertEqual
(
2
,
len
(
published_grades
))
self
.
assertEqual
(
2
,
len
(
published_grades
))
self
.
assertEqual
({
'value'
:
0.5
,
'max_value'
:
1
},
published_grades
[
-
1
])
self
.
call_handler
(
'do_attempt'
,
{
"val"
:
1
,
"input"
:
"99"
})
self
.
assertEqual
(
3
,
len
(
published_grades
))
self
.
assertEqual
({
'value'
:
1
,
'max_value'
:
1
},
published_grades
[
-
1
])
self
.
assertEqual
({
'value'
:
1
,
'max_value'
:
1
},
published_grades
[
-
1
])
def
test_do_attempt_final
(
self
):
def
test_do_attempt_final
(
self
):
...
@@ -195,7 +118,7 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
...
@@ -195,7 +118,7 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
expected_state
=
{
expected_state
=
{
"items"
:
{
"items"
:
{
"0"
:
{
"x_percent"
:
"33
%
"
,
"y_percent"
:
"11
%
"
,
"correct
_input
"
:
True
,
"zone"
:
self
.
ZONE_1
}
"0"
:
{
"x_percent"
:
"33
%
"
,
"y_percent"
:
"11
%
"
,
"correct"
:
True
,
"zone"
:
self
.
ZONE_1
}
},
},
"finished"
:
False
,
"finished"
:
False
,
'overall_feedback'
:
self
.
initial_feedback
(),
'overall_feedback'
:
self
.
initial_feedback
(),
...
@@ -204,24 +127,20 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
...
@@ -204,24 +127,20 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
data
=
{
"val"
:
1
,
"zone"
:
self
.
ZONE_2
,
"x_percent"
:
"22
%
"
,
"y_percent"
:
"22
%
"
}
data
=
{
"val"
:
1
,
"zone"
:
self
.
ZONE_2
,
"x_percent"
:
"22
%
"
,
"y_percent"
:
"22
%
"
}
res
=
self
.
call_handler
(
'do_attempt'
,
data
)
res
=
self
.
call_handler
(
'do_attempt'
,
data
)
data
=
{
"val"
:
1
,
"input"
:
"99"
}
res
=
self
.
call_handler
(
'do_attempt'
,
data
)
self
.
assertEqual
(
res
,
{
self
.
assertEqual
(
res
,
{
"overall_feedback"
:
self
.
FINAL_FEEDBACK
,
"overall_feedback"
:
self
.
FINAL_FEEDBACK
,
"finished"
:
True
,
"finished"
:
True
,
"correct"
:
True
,
"correct"
:
True
,
"correct_location"
:
True
,
"feedback"
:
self
.
FEEDBACK
[
1
][
"correct"
]
"feedback"
:
self
.
FEEDBACK
[
1
][
"correct"
]
})
})
expected_state
=
{
expected_state
=
{
"items"
:
{
"items"
:
{
"0"
:
{
"0"
:
{
"x_percent"
:
"33
%
"
,
"y_percent"
:
"11
%
"
,
"correct
_input
"
:
True
,
"zone"
:
self
.
ZONE_1
,
"x_percent"
:
"33
%
"
,
"y_percent"
:
"11
%
"
,
"correct"
:
True
,
"zone"
:
self
.
ZONE_1
,
},
},
"1"
:
{
"1"
:
{
"x_percent"
:
"22
%
"
,
"y_percent"
:
"22
%
"
,
"correct_input"
:
True
,
"zone"
:
self
.
ZONE_2
,
"x_percent"
:
"22
%
"
,
"y_percent"
:
"22
%
"
,
"correct"
:
True
,
"zone"
:
self
.
ZONE_2
,
"input"
:
"99"
,
}
}
},
},
"finished"
:
True
,
"finished"
:
True
,
...
...
tests/unit/test_basics.py
View file @
7fd8c2ed
...
@@ -46,7 +46,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
...
@@ -46,7 +46,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
self
.
assertEqual
(
zones
,
DEFAULT_DATA
[
"zones"
])
self
.
assertEqual
(
zones
,
DEFAULT_DATA
[
"zones"
])
# Items should contain no answer data:
# Items should contain no answer data:
self
.
assertEqual
(
items
,
[
self
.
assertEqual
(
items
,
[
{
"id"
:
i
,
"displayName"
:
display_name
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
,
"inputOptions"
:
False
}
{
"id"
:
i
,
"displayName"
:
display_name
,
"imageURL"
:
""
,
"expandedImageURL"
:
""
}
for
i
,
display_name
in
enumerate
(
for
i
,
display_name
in
enumerate
(
[
"Goes to the top"
,
"Goes to the middle"
,
"Goes to the bottom"
,
"I don't belong anywhere"
]
[
"Goes to the top"
,
"Goes to the middle"
,
"Goes to the bottom"
,
"I don't belong anywhere"
]
)
)
...
@@ -76,15 +76,15 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
...
@@ -76,15 +76,15 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
# Check the result:
# Check the result:
self
.
assertTrue
(
self
.
block
.
completed
)
self
.
assertTrue
(
self
.
block
.
completed
)
self
.
assertEqual
(
self
.
block
.
item_state
,
{
self
.
assertEqual
(
self
.
block
.
item_state
,
{
'0'
:
{
'x_percent'
:
'33
%
'
,
'y_percent'
:
'11
%
'
,
'zone'
:
TOP_ZONE_ID
},
'0'
:
{
'x_percent'
:
'33
%
'
,
'y_percent'
:
'11
%
'
,
'
correct'
:
True
,
'
zone'
:
TOP_ZONE_ID
},
'1'
:
{
'x_percent'
:
'67
%
'
,
'y_percent'
:
'80
%
'
,
'zone'
:
MIDDLE_ZONE_ID
},
'1'
:
{
'x_percent'
:
'67
%
'
,
'y_percent'
:
'80
%
'
,
'
correct'
:
True
,
'
zone'
:
MIDDLE_ZONE_ID
},
'2'
:
{
'x_percent'
:
'99
%
'
,
'y_percent'
:
'95
%
'
,
'zone'
:
BOTTOM_ZONE_ID
},
'2'
:
{
'x_percent'
:
'99
%
'
,
'y_percent'
:
'95
%
'
,
'
correct'
:
True
,
'
zone'
:
BOTTOM_ZONE_ID
},
})
})
self
.
assertEqual
(
self
.
call_handler
(
'get_user_state'
),
{
self
.
assertEqual
(
self
.
call_handler
(
'get_user_state'
),
{
'items'
:
{
'items'
:
{
'0'
:
{
'x_percent'
:
'33
%
'
,
'y_percent'
:
'11
%
'
,
'correct
_input
'
:
True
,
'zone'
:
TOP_ZONE_ID
},
'0'
:
{
'x_percent'
:
'33
%
'
,
'y_percent'
:
'11
%
'
,
'correct'
:
True
,
'zone'
:
TOP_ZONE_ID
},
'1'
:
{
'x_percent'
:
'67
%
'
,
'y_percent'
:
'80
%
'
,
'correct
_input
'
:
True
,
'zone'
:
MIDDLE_ZONE_ID
},
'1'
:
{
'x_percent'
:
'67
%
'
,
'y_percent'
:
'80
%
'
,
'correct'
:
True
,
'zone'
:
MIDDLE_ZONE_ID
},
'2'
:
{
'x_percent'
:
'99
%
'
,
'y_percent'
:
'95
%
'
,
'correct
_input
'
:
True
,
'zone'
:
BOTTOM_ZONE_ID
},
'2'
:
{
'x_percent'
:
'99
%
'
,
'y_percent'
:
'95
%
'
,
'correct'
:
True
,
'zone'
:
BOTTOM_ZONE_ID
},
},
},
'finished'
:
True
,
'finished'
:
True
,
'overall_feedback'
:
FINISH_FEEDBACK
,
'overall_feedback'
:
FINISH_FEEDBACK
,
...
...
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