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
cc6695c6
Commit
cc6695c6
authored
Jan 08, 2016
by
Tim Krones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Address review comments.
parent
99929eae
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
131 additions
and
140 deletions
+131
-140
drag_and_drop_v2/public/css/drag_and_drop.css
+2
-1
drag_and_drop_v2/public/js/drag_and_drop.js
+32
-40
drag_and_drop_v2/public/js/view.js
+2
-2
tests/integration/test_base.py
+3
-0
tests/integration/test_interaction.py
+92
-97
No files found.
drag_and_drop_v2/public/css/drag_and_drop.css
View file @
cc6695c6
...
@@ -116,7 +116,8 @@
...
@@ -116,7 +116,8 @@
/* Focused option */
/* Focused option */
.xblock--drag-and-drop
.drag-container
.item-bank
.option
:focus
,
.xblock--drag-and-drop
.drag-container
.item-bank
.option
:focus
,
.xblock--drag-and-drop
.drag-container
.item-bank
.option
:hover
{
.xblock--drag-and-drop
.drag-container
.item-bank
.option
:hover
,
.xblock--drag-and-drop
.drag-container
.item-bank
.option
[
aria-grabbed
=
'true'
]
{
outline-width
:
2px
;
outline-width
:
2px
;
outline-style
:
solid
;
outline-style
:
solid
;
outline-offset
:
-4px
;
outline-offset
:
-4px
;
...
...
drag_and_drop_v2/public/js/drag_and_drop.js
View file @
cc6695c6
...
@@ -13,7 +13,6 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -13,7 +13,6 @@ function DragAndDropBlock(runtime, element, configuration) {
var
__vdom
=
virtualDom
.
h
();
// blank virtual DOM
var
__vdom
=
virtualDom
.
h
();
// blank virtual DOM
// Keyboard accessibility
// Keyboard accessibility
var
CTRL
=
17
;
var
ESC
=
27
;
var
ESC
=
27
;
var
RET
=
13
;
var
RET
=
13
;
var
SPC
=
32
;
var
SPC
=
32
;
...
@@ -21,7 +20,6 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -21,7 +20,6 @@ function DragAndDropBlock(runtime, element, configuration) {
var
M
=
77
;
var
M
=
77
;
var
QUESTION_MARK
=
63
;
var
QUESTION_MARK
=
63
;
var
ctrlDown
=
false
;
var
placementMode
=
false
;
var
placementMode
=
false
;
var
$selectedItem
;
var
$selectedItem
;
var
$focusedElement
;
var
$focusedElement
;
...
@@ -213,16 +211,17 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -213,16 +211,17 @@ function DragAndDropBlock(runtime, element, configuration) {
});
});
};
};
var
isCycleKey
=
function
(
key
)
{
var
isCycleKey
=
function
(
evt
)
{
return
!
ctrlDown
&&
key
===
TAB
;
return
!
evt
.
ctrlKey
&&
!
evt
.
metaKey
&&
evt
.
which
===
TAB
;
};
};
var
isCancelKey
=
function
(
key
)
{
var
isCancelKey
=
function
(
evt
)
{
return
!
ctrlDown
&&
key
===
ESC
;
return
!
evt
.
ctrlKey
&&
!
evt
.
metaKey
&&
evt
.
which
===
ESC
;
};
};
var
isActionKey
=
function
(
key
)
{
var
isActionKey
=
function
(
evt
)
{
if
(
ctrlDown
)
{
var
key
=
evt
.
which
;
if
(
evt
.
ctrlKey
||
evt
.
metaKey
)
{
return
key
===
M
;
return
key
===
M
;
}
}
return
key
===
RET
||
key
===
SPC
;
return
key
===
RET
||
key
===
SPC
;
...
@@ -286,28 +285,20 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -286,28 +285,20 @@ function DragAndDropBlock(runtime, element, configuration) {
var
$zone
=
$
(
this
);
var
$zone
=
$
(
this
);
$zone
.
on
(
'keydown'
,
function
(
evt
)
{
$zone
.
on
(
'keydown'
,
function
(
evt
)
{
if
(
placementMode
)
{
if
(
placementMode
)
{
var
key
=
evt
.
which
;
if
(
isCycleKey
(
evt
))
{
if
(
key
===
CTRL
)
{
ctrlDown
=
true
;
return
;
}
if
(
isCycleKey
(
key
))
{
focusNextZone
(
evt
,
$zone
);
focusNextZone
(
evt
,
$zone
);
}
else
if
(
isCancelKey
(
key
))
{
}
else
if
(
isCancelKey
(
evt
))
{
evt
.
preventDefault
();
evt
.
preventDefault
();
placementMode
=
false
;
placementMode
=
false
;
}
else
if
(
isActionKey
(
key
))
{
releaseItem
(
$selectedItem
);
}
else
if
(
isActionKey
(
evt
))
{
evt
.
preventDefault
();
evt
.
preventDefault
();
placementMode
=
false
;
placementMode
=
false
;
placeItem
(
$zone
);
placeItem
(
$zone
);
releaseItem
(
$selectedItem
);
}
}
}
}
});
});
$zone
.
on
(
'keyup'
,
function
(
evt
)
{
if
(
evt
.
which
===
CTRL
)
{
ctrlDown
=
false
;
}
});
});
});
// Make zone accept items that are dropped using the mouse
// Make zone accept items that are dropped using the mouse
...
@@ -328,23 +319,14 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -328,23 +319,14 @@ function DragAndDropBlock(runtime, element, configuration) {
// Allow item to be "picked up" using the keyboard
// Allow item to be "picked up" using the keyboard
$item
.
on
(
'keydown'
,
function
(
evt
)
{
$item
.
on
(
'keydown'
,
function
(
evt
)
{
var
key
=
evt
.
which
;
if
(
isActionKey
(
evt
))
{
if
(
key
===
CTRL
)
{
ctrlDown
=
true
;
return
;
}
if
(
isActionKey
(
key
))
{
evt
.
preventDefault
();
evt
.
preventDefault
();
placementMode
=
true
;
placementMode
=
true
;
grabItem
(
$item
);
$selectedItem
=
$item
;
$selectedItem
=
$item
;
$root
.
find
(
'.target .zone'
).
first
().
focus
();
$root
.
find
(
'.target .zone'
).
first
().
focus
();
}
}
});
});
$item
.
on
(
'keyup'
,
function
(
evt
)
{
if
(
evt
.
which
===
CTRL
)
{
ctrlDown
=
false
;
}
});
// Make item draggable using the mouse
// Make item draggable using the mouse
try
{
try
{
...
@@ -355,18 +337,15 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -355,18 +337,15 @@ function DragAndDropBlock(runtime, element, configuration) {
revert
:
'invalid'
,
revert
:
'invalid'
,
revertDuration
:
150
,
revertDuration
:
150
,
start
:
function
(
evt
,
ui
)
{
start
:
function
(
evt
,
ui
)
{
var
item_id
=
$
(
this
).
data
(
'value'
);
var
$item
=
$
(
this
);
setGrabbedState
(
item_id
,
true
);
grabItem
(
$item
);
updateDOM
();
publishEvent
({
publishEvent
({
event_type
:
'xblock.drag-and-drop-v2.item.picked-up'
,
event_type
:
'xblock.drag-and-drop-v2.item.picked-up'
,
item_id
:
item_id
item_id
:
$item
.
data
(
'value'
),
});
});
},
},
stop
:
function
(
evt
,
ui
)
{
stop
:
function
(
evt
,
ui
)
{
var
item_id
=
$
(
this
).
data
(
'value'
);
releaseItem
(
$
(
this
));
setGrabbedState
(
item_id
,
false
);
updateDOM
();
}
}
});
});
}
catch
(
e
)
{
}
catch
(
e
)
{
...
@@ -376,6 +355,18 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -376,6 +355,18 @@ function DragAndDropBlock(runtime, element, configuration) {
});
});
};
};
var
grabItem
=
function
(
$item
)
{
var
item_id
=
$item
.
data
(
'value'
);
setGrabbedState
(
item_id
,
true
);
updateDOM
();
};
var
releaseItem
=
function
(
$item
)
{
var
item_id
=
$item
.
data
(
'value'
);
setGrabbedState
(
item_id
,
false
);
updateDOM
();
};
var
setGrabbedState
=
function
(
item_id
,
grabbed
)
{
var
setGrabbedState
=
function
(
item_id
,
grabbed
)
{
for
(
var
i
=
0
;
i
<
configuration
.
items
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
configuration
.
items
.
length
;
i
++
)
{
if
(
configuration
.
items
[
i
].
id
===
item_id
)
{
if
(
configuration
.
items
[
i
].
id
===
item_id
)
{
...
@@ -524,10 +515,11 @@ function DragAndDropBlock(runtime, element, configuration) {
...
@@ -524,10 +515,11 @@ function DragAndDropBlock(runtime, element, configuration) {
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
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
:
item_user_state
&&
(
'input'
in
item_user_state
||
item_user_state
.
correct_input
)
?
'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
,
input
:
input
,
displayName
:
item
.
displayName
,
displayName
:
item
.
displayName
,
...
...
drag_and_drop_v2/public/js/view.js
View file @
cc6695c6
...
@@ -176,8 +176,8 @@
...
@@ -176,8 +176,8 @@
h
(
'p'
,
gettext
(
'You can complete this exercise using only your keyboard.'
)),
h
(
'p'
,
gettext
(
'You can complete this exercise using only your keyboard.'
)),
h
(
'ul'
,
[
h
(
'ul'
,
[
h
(
'li'
,
gettext
(
'Use "Tab" and "Shift-Tab" to navigate between items and zones.'
)),
h
(
'li'
,
gettext
(
'Use "Tab" and "Shift-Tab" to navigate between items and zones.'
)),
h
(
'li'
,
gettext
(
'Press "Enter"
or "Space
" on an item to select it for dropping, then navigate to the zone you want to drop it on.'
)),
h
(
'li'
,
gettext
(
'Press "Enter"
, "Space", "Ctrl-m", or "⌘-m
" on an item to select it for dropping, then navigate to the zone you want to drop it on.'
)),
h
(
'li'
,
gettext
(
'Press "Enter"
or "Space
" to drop the item on the current zone.'
)),
h
(
'li'
,
gettext
(
'Press "Enter"
, "Space", "Ctrl-m", or "⌘-m
" to drop the item on the current zone.'
)),
h
(
'li'
,
gettext
(
'Press "Escape" if you want to cancel the drop operation (e.g. because you would like to select a different item).'
)),
h
(
'li'
,
gettext
(
'Press "Escape" if you want to cancel the drop operation (e.g. because you would like to select a different item).'
)),
h
(
'li'
,
gettext
(
'Press "?" at any time to bring up this dialog.'
)),
h
(
'li'
,
gettext
(
'Press "?" at any time to bring up this dialog.'
)),
])
])
...
...
tests/integration/test_base.py
View file @
cc6695c6
...
@@ -72,6 +72,9 @@ class BaseIntegrationTest(SeleniumBaseTest):
...
@@ -72,6 +72,9 @@ class BaseIntegrationTest(SeleniumBaseTest):
def
_get_keyboard_help_dialog
(
self
):
def
_get_keyboard_help_dialog
(
self
):
return
self
.
_page
.
find_element_by_css_selector
(
".keyboard-help .keyboard-help-dialog"
)
return
self
.
_page
.
find_element_by_css_selector
(
".keyboard-help .keyboard-help-dialog"
)
def
_get_reset_button
(
self
):
return
self
.
_page
.
find_element_by_css_selector
(
'.reset-button'
)
def
_get_feedback
(
self
):
def
_get_feedback
(
self
):
return
self
.
_page
.
find_element_by_css_selector
(
".feedback"
)
return
self
.
_page
.
find_element_by_css_selector
(
".feedback"
)
...
...
tests/integration/test_interaction.py
View file @
cc6695c6
...
@@ -31,12 +31,19 @@ class ItemDefinition(object):
...
@@ -31,12 +31,19 @@ class ItemDefinition(object):
class
InteractionTestBase
(
object
):
class
InteractionTestBase
(
object
):
@classmethod
@classmethod
def
_get_
correct_item_for
_zone
(
cls
,
items_map
):
def
_get_
items_with
_zone
(
cls
,
items_map
):
return
{
return
{
item_key
:
definition
for
item_key
,
definition
in
items_map
.
items
()
item_key
:
definition
for
item_key
,
definition
in
items_map
.
items
()
if
definition
.
zone_id
is
not
None
if
definition
.
zone_id
is
not
None
}
}
@classmethod
def
_get_items_without_zone
(
cls
,
items_map
):
return
{
item_key
:
definition
for
item_key
,
definition
in
items_map
.
items
()
if
definition
.
zone_id
is
None
}
def
setUp
(
self
):
def
setUp
(
self
):
super
(
InteractionTestBase
,
self
)
.
setUp
()
super
(
InteractionTestBase
,
self
)
.
setUp
()
...
@@ -64,17 +71,19 @@ class InteractionTestBase(object):
...
@@ -64,17 +71,19 @@ class InteractionTestBase(object):
element
=
self
.
_get_item_by_value
(
item_value
)
element
=
self
.
_get_item_by_value
(
item_value
)
return
element
.
find_element_by_class_name
(
'numerical-input'
)
return
element
.
find_element_by_class_name
(
'numerical-input'
)
def
_send_input
(
self
,
item_value
,
value
):
def
_get_zone_position
(
self
,
zone_id
):
element
=
self
.
_get_item_by_value
(
item_value
)
return
self
.
browser
.
execute_script
(
self
.
wait_until_visible
(
element
)
'return $("div[data-zone=
\'
{zone_id}
\'
]").prevAll(".zone").length'
.
format
(
zone_id
=
zone_id
)
element
.
find_element_by_class_name
(
'input'
)
.
send_keys
(
value
)
)
element
.
find_element_by_class_name
(
'submit-input'
)
.
click
()
def
get_feedback_popup
(
self
):
def
_focus_item
(
self
,
item_position
):
return
self
.
_page
.
find_element_by_css_selector
(
".popup-content"
)
self
.
browser
.
execute_script
(
"$('.option:nth-child({n})').focus()"
.
format
(
n
=
item_position
+
1
)
)
def
get_reset_button
(
self
):
def
place_item
(
self
,
item_value
,
zone_id
,
action_key
=
None
):
return
self
.
_page
.
find_element_by_css_selector
(
'.reset-button'
)
if
action_key
is
None
:
self
.
drag_item_to_zone
(
item_value
,
zone_id
)
else
:
self
.
move_item_to_zone
(
item_value
,
zone_id
,
action_key
)
def
drag_item_to_zone
(
self
,
item_value
,
zone_id
):
def
drag_item_to_zone
(
self
,
item_value
,
zone_id
):
element
=
self
.
_get_item_by_value
(
item_value
)
element
=
self
.
_get_item_by_value
(
item_value
)
...
@@ -86,27 +95,29 @@ class InteractionTestBase(object):
...
@@ -86,27 +95,29 @@ class InteractionTestBase(object):
# Get item position
# Get item position
item_position
=
item_value
item_position
=
item_value
# Get zone position
# Get zone position
zone_position
=
self
.
get_zone_position
(
zone_id
)
zone_position
=
self
.
_
get_zone_position
(
zone_id
)
self
.
focus_item
(
0
)
self
.
_
focus_item
(
0
)
focused_item
=
self
.
_get_item_by_value
(
0
)
focused_item
=
self
.
_get_item_by_value
(
0
)
for
i
in
range
(
item_position
):
for
i
in
range
(
item_position
):
focused_item
.
send_keys
(
Keys
.
TAB
)
focused_item
.
send_keys
(
Keys
.
TAB
)
focused_item
=
self
.
_get_item_by_value
(
i
+
1
)
focused_item
=
self
.
_get_item_by_value
(
i
+
1
)
focused_item
.
send_keys
(
action_key
)
# Focus is on first *zone* now
focused_item
.
send_keys
(
action_key
)
# Focus is on first *zone* now
self
.
assert_grabbed_item
(
focused_item
)
focused_zone
=
self
.
_get_zone_by_id
(
ZONES_MAP
[
0
])
focused_zone
=
self
.
_get_zone_by_id
(
ZONES_MAP
[
0
])
for
i
in
range
(
zone_position
):
for
i
in
range
(
zone_position
):
focused_zone
.
send_keys
(
Keys
.
TAB
)
focused_zone
.
send_keys
(
Keys
.
TAB
)
focused_zone
=
self
.
_get_zone_by_id
(
ZONES_MAP
[
i
+
1
])
focused_zone
=
self
.
_get_zone_by_id
(
ZONES_MAP
[
i
+
1
])
focused_zone
.
send_keys
(
action_key
)
focused_zone
.
send_keys
(
action_key
)
def
get_zone_position
(
self
,
zone_id
):
def
send_input
(
self
,
item_value
,
value
):
return
self
.
browser
.
execute_script
(
element
=
self
.
_get_item_by_value
(
item_value
)
'return $("div[data-zone=
\'
{zone_id}
\'
]").prevAll(".zone").length'
.
format
(
zone_id
=
zone_id
)
self
.
wait_until_visible
(
element
)
)
element
.
find_element_by_class_name
(
'input'
)
.
send_keys
(
value
)
element
.
find_element_by_class_name
(
'submit-input'
)
.
click
()
def
focus_item
(
self
,
item_position
):
def
assert_grabbed_item
(
self
,
item
):
self
.
browser
.
execute_script
(
"$('.option:nth-child({n})').focus()"
.
format
(
n
=
item_position
+
1
)
)
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'true'
)
def
assert_placed_item
(
self
,
item_value
,
zone_id
):
def
assert_placed_item
(
self
,
item_value
,
zone_id
):
item
=
self
.
_get_placed_item_by_value
(
item_value
)
item
=
self
.
_get_placed_item_by_value
(
item_value
)
...
@@ -125,6 +136,7 @@ class InteractionTestBase(object):
...
@@ -125,6 +136,7 @@ class InteractionTestBase(object):
item
=
self
.
_get_item_by_value
(
item_value
)
item
=
self
.
_get_item_by_value
(
item_value
)
item_content
=
item
.
find_element_by_css_selector
(
'.item-content'
)
item_content
=
item
.
find_element_by_css_selector
(
'.item-content'
)
self
.
assertEqual
(
item
.
get_attribute
(
'class'
),
'option ui-draggable'
)
self
.
assertEqual
(
item
.
get_attribute
(
'tabindex'
),
'0'
)
self
.
assertEqual
(
item
.
get_attribute
(
'tabindex'
),
'0'
)
self
.
assertEqual
(
item
.
get_attribute
(
'draggable'
),
'true'
)
self
.
assertEqual
(
item
.
get_attribute
(
'draggable'
),
'true'
)
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'false'
)
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'false'
)
...
@@ -138,43 +150,40 @@ class InteractionTestBase(object):
...
@@ -138,43 +150,40 @@ class InteractionTestBase(object):
else
:
else
:
self
.
fail
(
'Reverted item should not have .sr description.'
)
self
.
fail
(
'Reverted item should not have .sr description.'
)
def
parameterized_item_positive_feedback_on_good_move
(
def
assert_decoy_items
(
self
,
items_map
):
self
,
items_map
,
scroll_down
=
100
,
use_keyboard
=
False
,
action_key
=
Keys
.
RETURN
decoy_items
=
self
.
_get_items_without_zone
(
items_map
)
):
for
item_key
in
decoy_items
:
item
=
self
.
_get_item_by_value
(
item_key
)
self
.
assertEqual
(
item
.
get_attribute
(
'class'
),
'option fade'
)
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'false'
)
self
.
assertEqual
(
item
.
get_attribute
(
'data-drag-disabled'
),
'true'
)
def
parameterized_item_positive_feedback_on_good_move
(
self
,
items_map
,
scroll_down
=
100
,
action_key
=
None
):
# Scroll drop zones into view to make sure Selenium can successfully drop items
# Scroll drop zones into view to make sure Selenium can successfully drop items
self
.
scroll_down
(
pixels
=
scroll_down
)
self
.
scroll_down
(
pixels
=
scroll_down
)
for
definition
in
self
.
_get_
correct_item_for
_zone
(
items_map
)
.
values
():
for
definition
in
self
.
_get_
items_with
_zone
(
items_map
)
.
values
():
if
not
definition
.
input
:
if
not
definition
.
input
:
if
use_keyboard
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
move_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
feedback_popup_content
=
self
.
_get_popup_content
()
else
:
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup_content
)
self
.
drag_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
)
feedback_popup
=
self
.
get_feedback_popup
()
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
def
parameterized_item_positive_feedback_on_good_input
(
def
parameterized_item_positive_feedback_on_good_input
(
self
,
items_map
,
scroll_down
=
100
,
action_key
=
None
):
self
,
items_map
,
scroll_down
=
100
,
use_keyboard
=
False
,
action_key
=
Keys
.
RETURN
):
self
.
scroll_down
(
pixels
=
scroll_down
)
self
.
scroll_down
(
pixels
=
scroll_down
)
feedback_popup
=
self
.
get_feedback_popup
()
feedback_popup
_content
=
self
.
_get_popup_content
()
for
definition
in
self
.
_get_
correct_item_for
_zone
(
items_map
)
.
values
():
for
definition
in
self
.
_get_
items_with
_zone
(
items_map
)
.
values
():
if
definition
.
input
:
if
definition
.
input
:
if
use_keyboard
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
move_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
send_input
(
definition
.
item_id
,
definition
.
input
)
else
:
self
.
drag_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
_send_input
(
definition
.
item_id
,
definition
.
input
)
input_div
=
self
.
_get_input_div_by_value
(
definition
.
item_id
)
input_div
=
self
.
_get_input_div_by_value
(
definition
.
item_id
)
self
.
wait_until_has_class
(
'correct'
,
input_div
)
self
.
wait_until_has_class
(
'correct'
,
input_div
)
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup
)
self
.
wait_until_html_in
(
definition
.
feedback_positive
,
feedback_popup
_content
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
def
parameterized_item_negative_feedback_on_bad_move
(
def
parameterized_item_negative_feedback_on_bad_move
(
self
,
items_map
,
all_zones
,
scroll_down
=
100
,
action_key
=
None
):
self
,
items_map
,
all_zones
,
scroll_down
=
100
,
use_keyboard
=
False
,
action_key
=
Keys
.
RETURN
feedback_popup_content
=
self
.
_get_popup_content
()
):
feedback_popup
=
self
.
get_feedback_popup
()
# Scroll drop zones into view to make sure Selenium can successfully drop items
# Scroll drop zones into view to make sure Selenium can successfully drop items
self
.
scroll_down
(
pixels
=
scroll_down
)
self
.
scroll_down
(
pixels
=
scroll_down
)
...
@@ -183,40 +192,30 @@ class InteractionTestBase(object):
...
@@ -183,40 +192,30 @@ class InteractionTestBase(object):
for
zone
in
all_zones
:
for
zone
in
all_zones
:
if
zone
==
definition
.
zone_id
:
if
zone
==
definition
.
zone_id
:
continue
continue
if
use_keyboard
:
self
.
place_item
(
definition
.
item_id
,
zone
,
action_key
)
self
.
move_item_to_zone
(
definition
.
item_id
,
zone
,
action_key
)
self
.
wait_until_html_in
(
definition
.
feedback_negative
,
feedback_popup_content
)
else
:
self
.
drag_item_to_zone
(
definition
.
item_id
,
zone
)
self
.
wait_until_html_in
(
definition
.
feedback_negative
,
feedback_popup
)
self
.
assert_reverted_item
(
definition
.
item_id
)
self
.
assert_reverted_item
(
definition
.
item_id
)
def
parameterized_item_negative_feedback_on_bad_input
(
def
parameterized_item_negative_feedback_on_bad_input
(
self
,
items_map
,
scroll_down
=
100
,
action_key
=
None
):
self
,
items_map
,
scroll_down
=
100
,
use_keyboard
=
False
,
action_key
=
Keys
.
RETURN
feedback_popup_content
=
self
.
_get_popup_content
()
):
feedback_popup
=
self
.
get_feedback_popup
()
# Scroll drop zones into view to make sure Selenium can successfully drop items
# Scroll drop zones into view to make sure Selenium can successfully drop items
self
.
scroll_down
(
pixels
=
scroll_down
)
self
.
scroll_down
(
pixels
=
scroll_down
)
for
definition
in
self
.
_get_
correct_item_for
_zone
(
items_map
)
.
values
():
for
definition
in
self
.
_get_
items_with
_zone
(
items_map
)
.
values
():
if
definition
.
input
:
if
definition
.
input
:
if
use_keyboard
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
move_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
send_input
(
definition
.
item_id
,
'1999999'
)
else
:
self
.
drag_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
_send_input
(
definition
.
item_id
,
'1999999'
)
input_div
=
self
.
_get_input_div_by_value
(
definition
.
item_id
)
input_div
=
self
.
_get_input_div_by_value
(
definition
.
item_id
)
self
.
wait_until_has_class
(
'incorrect'
,
input_div
)
self
.
wait_until_has_class
(
'incorrect'
,
input_div
)
self
.
wait_until_html_in
(
definition
.
feedback_negative
,
feedback_popup
)
self
.
wait_until_html_in
(
definition
.
feedback_negative
,
feedback_popup
_content
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
def
parameterized_final_feedback_and_reset
(
def
parameterized_final_feedback_and_reset
(
self
,
items_map
,
feedback
,
scroll_down
=
100
,
action_key
=
None
):
self
,
items_map
,
feedback
,
scroll_down
=
100
,
use_keyboard
=
False
,
action_key
=
Keys
.
RETURN
):
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
items
=
self
.
_get_
correct_item_for
_zone
(
items_map
)
items
=
self
.
_get_
items_with
_zone
(
items_map
)
def
get_locations
():
def
get_locations
():
return
{
item_id
:
self
.
_get_item_by_value
(
item_id
)
.
location
for
item_id
in
items
.
keys
()}
return
{
item_id
:
self
.
_get_item_by_value
(
item_id
)
.
location
for
item_id
in
items
.
keys
()}
...
@@ -227,23 +226,23 @@ class InteractionTestBase(object):
...
@@ -227,23 +226,23 @@ class InteractionTestBase(object):
self
.
scroll_down
(
pixels
=
scroll_down
)
self
.
scroll_down
(
pixels
=
scroll_down
)
for
item_key
,
definition
in
items
.
items
():
for
item_key
,
definition
in
items
.
items
():
if
use_keyboard
:
self
.
place_item
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
self
.
move_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
,
action_key
)
else
:
self
.
drag_item_to_zone
(
definition
.
item_id
,
definition
.
zone_id
)
if
definition
.
input
:
if
definition
.
input
:
self
.
_
send_input
(
item_key
,
definition
.
input
)
self
.
send_input
(
item_key
,
definition
.
input
)
input_div
=
self
.
_get_input_div_by_value
(
item_key
)
input_div
=
self
.
_get_input_div_by_value
(
item_key
)
self
.
wait_until_has_class
(
'correct'
,
input_div
)
self
.
wait_until_has_class
(
'correct'
,
input_div
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
assert_placed_item
(
definition
.
item_id
,
definition
.
zone_id
)
self
.
wait_until_html_in
(
feedback
[
'final'
],
self
.
_get_feedback_message
())
self
.
wait_until_html_in
(
feedback
[
'final'
],
self
.
_get_feedback_message
())
# Check decoy items
self
.
assert_decoy_items
(
items_map
)
# Scroll "Reset exercise" button into view to make sure Selenium can successfully click it
# Scroll "Reset exercise" button into view to make sure Selenium can successfully click it
self
.
scroll_down
(
pixels
=
scroll_down
+
150
)
self
.
scroll_down
(
pixels
=
scroll_down
+
150
)
reset
=
self
.
get_reset_button
()
reset
=
self
.
_
get_reset_button
()
if
use_keyboard
:
if
action_key
is
not
None
:
# Using keyboard to interact with block
:
reset
.
send_keys
(
Keys
.
RETURN
)
reset
.
send_keys
(
Keys
.
RETURN
)
else
:
else
:
reset
.
click
()
reset
.
click
()
...
@@ -281,6 +280,12 @@ class InteractionTestBase(object):
...
@@ -281,6 +280,12 @@ class InteractionTestBase(object):
self
.
assertFalse
(
dialog_modal_overlay
.
is_displayed
())
self
.
assertFalse
(
dialog_modal_overlay
.
is_displayed
())
self
.
assertFalse
(
dialog_modal
.
is_displayed
())
self
.
assertFalse
(
dialog_modal
.
is_displayed
())
if
use_keyboard
:
# Try again with "?" key
self
.
_page
.
send_keys
(
"?"
)
self
.
assertTrue
(
dialog_modal_overlay
.
is_displayed
())
self
.
assertTrue
(
dialog_modal
.
is_displayed
())
class
BasicInteractionTest
(
InteractionTestBase
):
class
BasicInteractionTest
(
InteractionTestBase
):
"""
"""
...
@@ -333,38 +338,28 @@ class BasicInteractionTest(InteractionTestBase):
...
@@ -333,38 +338,28 @@ class BasicInteractionTest(InteractionTestBase):
@ddt
@ddt
class
KeyboardInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
class
KeyboardInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_positive_feedback_on_good_move
(
self
,
action_key
):
def
test_item_positive_feedback_on_good_move_with_keyboard
(
self
,
action_key
):
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
,
action_key
=
action_key
)
self
.
items_map
,
use_keyboard
=
True
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_positive_feedback_on_good_input
(
self
,
action_key
):
def
test_item_positive_feedback_on_good_input_with_keyboard
(
self
,
action_key
):
self
.
parameterized_item_positive_feedback_on_good_input
(
self
.
parameterized_item_positive_feedback_on_good_input
(
self
.
items_map
,
action_key
=
action_key
)
self
.
items_map
,
use_keyboard
=
True
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_negative_feedback_on_bad_move
(
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
.
parameterized_item_negative_feedback_on_bad_move
(
self
.
items_map
,
self
.
all_zones
,
action_key
=
action_key
)
self
.
items_map
,
self
.
all_zones
,
use_keyboard
=
True
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_negative_feedback_on_bad_input
(
self
,
action_key
):
def
test_item_negative_feedback_on_bad_input_with_keyboard
(
self
,
action_key
):
self
.
parameterized_item_negative_feedback_on_bad_input
(
self
.
parameterized_item_negative_feedback_on_bad_input
(
self
.
items_map
,
action_key
=
action_key
)
self
.
items_map
,
use_keyboard
=
True
,
action_key
=
action_key
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
)
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_final_feedback_and_reset
(
self
,
action_key
):
def
test_final_feedback_and_reset_with_keyboard
(
self
,
action_key
):
self
.
parameterized_final_feedback_and_reset
(
self
.
parameterized_final_feedback_and_reset
(
self
.
items_map
,
self
.
feedback
,
action_key
=
action_key
)
self
.
items_map
,
self
.
feedback
,
use_keyboard
=
True
,
action_key
=
action_key
)
def
test_keyboard_help
(
self
,
use_keyboard
=
True
):
def
test_keyboard_help
(
self
):
self
.
interact_with_keyboard_help
()
self
.
interact_with_keyboard_help
(
use_keyboard
=
True
)
class
CustomDataInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
class
CustomDataInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
...
...
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