Commit 8cb4774d by Braden MacDonald Committed by GitHub

Merge pull request #110 from open-craft/ekolpakov/improve-keyboard-instructions

Improve keyboard and SR instructions
parents 34c41163 77df9f5f
......@@ -43,6 +43,7 @@
display: inline-block;
color: #5e5e5e;
font-size: 0.875em;
margin-bottom: 0.5em;
}
.xblock--drag-and-drop .problem p {
......@@ -444,8 +445,6 @@
.xblock--drag-and-drop .btn-brand {
display: inline-block;
font-weight: normal;
background: #0079bc;
color: #fcfcfc;
-webkit-transition: color 0.125s ease-in-out 0s, border-color 0.125s ease-in-out 0s, background 0.125s ease-in-out 0s, box-shadow 0.125s ease-in-out 0s;
-moz-transition: color 0.125s ease-in-out 0s, border-color 0.125s ease-in-out 0s, background 0.125s ease-in-out 0s, box-shadow 0.125s ease-in-out 0s;
transition: color 0.125s ease-in-out 0s, border-color 0.125s ease-in-out 0s, background 0.125s ease-in-out 0s, box-shadow 0.125s ease-in-out 0s;
......@@ -472,6 +471,12 @@
font-size: 0.875em;
}
.xblock--drag-and-drop .btn-link {
padding: 1px;
font-size: 0.875em;
font-weight: normal;
}
.xblock--drag-and-drop .btn-default:hover,
.xblock--drag-and-drop .btn-default.is-hovered,
.xblock--drag-and-drop .btn-default:focus,
......@@ -625,6 +630,10 @@
display: block;
}
.xblock--drag-and-drop .btn-link .btn-icon {
display: inline;
}
/*** ACTIONS TOOLBAR END ***/
/*** KEYBOARD HELP ***/
......
......@@ -53,6 +53,7 @@ function DragAndDropTemplates(configuration) {
var itemTemplate = function(item, ctx) {
// Define properties
var descriptionClassName = "sr description";
var className = (item.class_name) ? item.class_name : "";
var zone = getZone(item.zone, ctx) || {};
if (item.has_image) {
......@@ -69,7 +70,8 @@ function DragAndDropTemplates(configuration) {
'draggable': !item.drag_disabled,
'aria-grabbed': item.grabbed,
'data-value': item.value,
'tabindex': item.focusable ? 0 : undefined
'tabindex': item.focusable ? 0 : undefined,
'aria-live': 'polite'
};
var style = {};
if (item.background_color) {
......@@ -98,13 +100,11 @@ function DragAndDropTemplates(configuration) {
$.extend(style, bankItemWidthStyles(item, ctx));
}
// Define children
var children = [
itemSpinnerTemplate(item)
];
var item_content = itemContentTemplate(item);
var item_description = null;
// Insert information about zone in which this item has been placed
var item_description_id = configuration.url_name + '-item-' + item.value + '-description';
item_content.properties.attributes = { 'aria-describedby': item_description_id };
if (item.is_placed) {
var zone_title = (zone.title || "Unknown Zone"); // This "Unknown" text should never be seen, so does not need i18n
var description_content;
......@@ -116,20 +116,23 @@ function DragAndDropTemplates(configuration) {
// so all placed items are always in the correct zone.
description_content = gettext('Correctly placed in: {zone_title}').replace('{zone_title}', zone_title);
}
var item_description = h(
var item_description_id = configuration.url_name + '-item-' + item.value + '-description';
item_content.properties.attributes = { 'aria-describedby': item_description_id };
item_description = h(
'div',
{ key: item.value + '-description', id: item_description_id, className: 'sr' },
{ key: item.value + '-description', id: item_description_id, className: descriptionClassName },
description_content
);
} else {
var item_description = h(
'div',
{ id: item_description_id, className: 'sr'},
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.')
);
}
children.splice(1, 0, item_description);
children.splice(1, 0, item_content);
var itemSRNote = h(
'span.sr.draggable',
(item.grabbed) ? gettext(", draggable, grabbed") : gettext(", draggable")
);
var children = [
itemSpinnerTemplate(item), item_content, itemSRNote, item_description
];
return (
h(
'div.option',
......@@ -219,7 +222,7 @@ function DragAndDropTemplates(configuration) {
},
[
h('p', { className: className }, zone.title),
h('p', { className: 'zone-description sr' }, zone.description),
h('p', { className: 'zone-description sr' }, zone.description || gettext("droppable")),
h(item_wrapper, renderCollection(itemTemplate, items_in_zone, ctx)),
zone_description
]
......@@ -252,54 +255,25 @@ function DragAndDropTemplates(configuration) {
);
};
var popupTemplate = function(ctx) {
var popupSelector = 'div.popup';
if (ctx.popup_html && !ctx.last_action_correct) {
popupSelector += '.popup-incorrect';
}
return (
h(
"div.popup-wrapper",
{
attributes: {
'aria-live': 'polite',
'aria-atomic': 'true',
'aria-relevant': 'additions',
}
},
[
h(
popupSelector,
{
style: {display: ctx.popup_html ? 'block' : 'none'},
},
[
h('div.close.icon-remove-sign.fa-times-circle'),
h('p.popup-content', {innerHTML: ctx.popup_html}),
]
)
]
)
)
};
var keyboardHelpPopupTemplate = function(ctx) {
var labelledby_id = 'modal-window-title-'+configuration.url_name;
return (
h('div.keyboard-help-dialog', [
h('div.modal-window-overlay'),
h('div.modal-window', {attributes: {role: 'dialog', 'aria-labelledby': labelledby_id}}, [
h('div.modal-window', {attributes: {role: 'dialog', 'aria-labelledby': labelledby_id, tabindex: -1}}, [
h('div.modal-header', [
h('h2.modal-window-title#'+labelledby_id, gettext('Keyboard Help'))
]),
h('div.modal-content', [
h('p', gettext('You can complete this problem using only your keyboard.')),
h('p.sr', gettext('This is a screen reader-friendly problem.')),
h('p.sr', gettext('Drag and Drop problems consist of draggable items and dropzones. Users should select a draggable item with their keyboard and then navigate to an appropriate dropzone to drop it.')),
h('p', gettext('You can complete this problem using only your keyboard by following the guidance below:')),
h('ul', [
h('li', gettext('Use "Tab" and "Shift-Tab" to navigate between items and zones.')),
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", "Space", "Ctrl-m", or "⌘-m" to drop the item on the current zone.')),
h('li', gettext('Press "Esc" if you want to cancel the drop operation (for example, to select a different item).')),
h('li', gettext('Use only TAB and SHIFT+TAB to navigate between draggable items and drop zones.')),
h('li', gettext('Press CTRL+M to select a draggable item (effectively picking it up).')),
h('li', gettext('Navigate using TAB and SHIFT+TAB to the appropriate dropzone and press CTRL+M once more to drop it here.')),
h('li', gettext('Press ESC if you want to cancel the drop operation (for example, to select a different item).')),
h('li', gettext('TAB back to the list of draggable items and repeat this process until all of the draggable items have been placed on their respective dropzones.')),
])
]),
h('div.modal-actions', [
......@@ -370,7 +344,6 @@ function DragAndDropTemplates(configuration) {
}
return(
h("section.action-toolbar-item.sidebar-buttons", {}, [
sidebarButtonTemplate("keyboard-help-button", "fa-question", gettext('Keyboard Help')),
sidebarButtonTemplate("reset-button", "fa-refresh", gettext('Reset'), ctx.disable_reset_button),
showAnswerButton,
])
......@@ -423,7 +396,7 @@ function DragAndDropTemplates(configuration) {
h(
'span.sr',
{
innerHTML: gettext("Close item feedback popup")
innerHTML: gettext("Close")
}
),
h(
......@@ -441,6 +414,22 @@ function DragAndDropTemplates(configuration) {
)
};
var forwardKeyboardHelpButtonTemplate = function(ctx) {
return h(
'button.unbutton.btn-link.keyboard-help-button',
[
h(
"span.btn-icon.fa.fa-keyboard-o",
{attributes: {"aria-hidden": true}}
),
// appending space is the simplest way to avoid sticking text to the button, but also to have
// them underlined together on hover. When margin was used there was a gap in underlining
" ",
gettext('Keyboard Help')
]
);
};
var progressTemplate = function(ctx) {
// Formats a number to 4 decimals without trailing zeros
// (1.00 -> '1'; 1.50 -> '1.5'; 1.333333333 -> '1.3333').
......@@ -504,26 +493,29 @@ function DragAndDropTemplates(configuration) {
var is_item_placed = function(i) { return i.is_placed; };
var items_placed = $.grep(ctx.items, is_item_placed);
var items_in_bank = $.grep(ctx.items, is_item_placed, true);
var item_bank_properties = {};
if (ctx.item_bank_focusable) {
item_bank_properties.attributes = {
'tabindex': 0,
'dropzone': 'move',
'aria-dropeffect': 'move',
'role': 'button'
var item_bank_properties = {
attributes: {
'role': 'group',
'aria-label': gettext('Item Bank')
}
};
if (ctx.item_bank_focusable) {
item_bank_properties.attributes['tabindex'] = 0;
item_bank_properties.attributes['dropzone'] = 'move';
item_bank_properties.attributes['aria-dropeffect'] = 'move';
item_bank_properties.attributes['role'] = 'button';
}
return (
h('section.themed-xblock.xblock--drag-and-drop', [
problemTitle,
problemProgress,
h('div', [forwardKeyboardHelpButtonTemplate(ctx)]),
h('section.problem', [
problemHeader,
h('p', {innerHTML: ctx.problem_html}),
]),
h('section.drag-container', {}, [
h('div.item-bank', item_bank_properties, [
h('p', { className: 'zone-description sr' }, gettext('Item Bank')),
renderCollection(itemTemplate, items_in_bank, ctx),
renderCollection(itemPlaceholderTemplate, items_placed, ctx)
]),
......@@ -688,11 +680,10 @@ function DragAndDropBlock(runtime, element, configuration) {
// Show dialog
var $keyboardHelpDialog = $root.find('.keyboard-help-dialog');
$keyboardHelpDialog.find('.modal-window-overlay').show();
$keyboardHelpDialog.find('.modal-window').show();
$keyboardHelpDialog.find('.modal-window').show().focus();
// Handle focus
$focusedElement = $(':focus');
focusModalButton();
// Set up event handlers
$(document).on('keydown', keyboardEventDispatcher);
......@@ -851,11 +842,7 @@ function DragAndDropBlock(runtime, element, configuration) {
};
var isActionKey = function(evt) {
var key = evt.which;
if (evt.ctrlKey || evt.metaKey) {
return key === M;
}
return key === RET || key === SPC;
return evt.which == RET || (evt.ctrlKey && evt.which == M);
};
var isSpaceKey = function(evt) {
......
......@@ -449,6 +449,14 @@ msgstr ""
msgid "Correctly placed in: {zone_title}"
msgstr ""
#: drag_and_drop_v2/public/js/drag_and_drop.js:137
msgid ", draggable, grabbed"
msgstr ""
#: drag_and_drop_v2/public/js/drag_and_drop.js:137
msgid ", draggable"
msgstr ""
#: public/js/drag_and_drop.js
msgid "Reset"
msgstr ""
......@@ -473,32 +481,51 @@ msgstr ""
msgid "Keyboard Help"
msgstr ""
#: public/js/drag_and_drop.js
msgid "You can complete this problem using only your keyboard."
#: drag_and_drop_v2/public/js/drag_and_drop.js:305
msgid "This is a screen reader-friendly problem"
msgstr ""
#: public/js/drag_and_drop.js
msgid "Use \"Tab\" and \"Shift-Tab\" to navigate between items and zones."
#: drag_and_drop_v2/public/js/drag_and_drop.js:306
msgid ""
"You can complete this problem using only your keyboard by following the "
"guidance below:"
msgstr ""
#: public/js/drag_and_drop.js
#: drag_and_drop_v2/public/js/drag_and_drop.js:307
msgid ""
"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."
"Drag and Drop problems consist of draggable items and dropzones. Users "
"should select a draggable item with their keyboard and then navigate to an "
"appropriate dropzone to drop it."
msgstr ""
#: public/js/drag_and_drop.js
#: drag_and_drop_v2/public/js/drag_and_drop.js:309
msgid ""
"Press \"Enter\", \"Space\", \"Ctrl-m\", or \"⌘-m\" to drop the item on the "
"current zone."
"Use only TAB and SHIFT+TAB to navigate between draggable items and drop "
"zones."
msgstr ""
#: public/js/drag_and_drop.js
#: drag_and_drop_v2/public/js/drag_and_drop.js:310
msgid "Press CTRL+M to select a draggable item (effectively picking it up)."
msgstr ""
#: drag_and_drop_v2/public/js/drag_and_drop.js:311
msgid ""
"Press \"Esc\" if you want to cancel the drop operation (for example, to "
"Navigate using TAB and SHIFT+TAB to the appropriate dropzone and press CTRL"
"+M once more to drop it here."
msgstr ""
#: drag_and_drop_v2/public/js/drag_and_drop.js:312
msgid ""
"Press ESC if you want to cancel the drop operation (for example, to "
"select a different item)."
msgstr ""
#: drag_and_drop_v2/public/js/drag_and_drop.js:313
msgid ""
"TAB back to the list of draggable items and repeat this process until all of "
"the draggable items have been placed on their respective dropzones."
msgstr ""
#: public/js/drag_and_drop.js
msgid "OK"
msgstr ""
......@@ -532,7 +559,7 @@ msgid "None"
msgstr ""
#: public/js/drag_and_drop_edit.js
msgid "Close item feedback popup"
msgid "Close"
msgstr ""
......
......@@ -521,6 +521,14 @@ msgstr "Pläçéd ïn: {zone_title} Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт
msgid "Correctly placed in: {zone_title}"
msgstr "Çörréçtlý pläçéd ïn: {zone_title} Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ", draggable, grabbed"
msgstr ", dräggäßlé, gräßßéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#"
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ", draggable"
msgstr "dräggäßlé Ⱡ'σяєм ιρѕυм ∂σł#"
#: public/js/drag_and_drop.js
msgid "Reset"
msgstr "Rését Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
......@@ -545,42 +553,79 @@ msgstr "Féédßäçk Ⱡ'σяєм ιρѕυм ∂#"
msgid "Keyboard Help"
msgstr "Kéýßöärd Hélp Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: public/js/drag_and_drop.js
msgid "You can complete this problem using only your keyboard."
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid "This is a screen reader-friendly problem."
msgstr ""
"Ýöü çän çömplété thïs prößlém üsïng önlý ýöür kéýßöärd. Ⱡ'σяєм ιρѕυм ∂σłσя "
"ѕιт αмєт, ¢σηѕє¢тєтυя α#"
"Thïs ïs ä sçréén réädér-frïéndlý prößlém. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυя#"
#: public/js/drag_and_drop.js
msgid "Use \"Tab\" and \"Shift-Tab\" to navigate between items and zones."
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ""
"You can complete this problem using only your keyboard by following the "
"guidance below:"
msgstr ""
"Ûsé \"Täß\" änd \"Shïft-Täß\" tö nävïgäté ßétwéén ïtéms änd zönés. Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
"Ýöü çän çömplété thïs prößlém üsïng önlý ýöür kéýßöärd ßý föllöwïng thé "
"güïdänçé ßélöw: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#"
#: public/js/drag_and_drop.js
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ""
"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."
"Drag and Drop problems consist of draggable items and dropzones. Users "
"should select a draggable item with their keyboard and then navigate to an "
"appropriate dropzone to drop it."
msgstr ""
"Préss \"Éntér\", \"Späçé\", \"Çtrl-m\", ör \"⌘-m\" ön än ïtém tö séléçt ït "
"för dröppïng, thén nävïgäté tö thé zöné ýöü wänt tö dröp ït ön. Ⱡ'#"
"Dräg änd Dröp prößléms çönsïst öf dräggäßlé ïtéms änd dröpzönés. Ûsérs "
"shöüld séléçt ä dräggäßlé ïtém wïth théïr kéýßöärd änd thén nävïgäté tö än "
"äppröprïäté dröpzöné tö dröp ït. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя "
"α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα"
" αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ "
"ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη "
"яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα "
"ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη #"
#: public/js/drag_and_drop.js
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ""
"Press \"Enter\", \"Space\", \"Ctrl-m\", or \"⌘-m\" to drop the item on the "
"current zone."
"Use only TAB and SHIFT+TAB to navigate between draggable items and drop "
"zones."
msgstr ""
"Préss \"Éntér\", \"Späçé\", \"Çtrl-m\", ör \"⌘-m\" tö dröp thé ïtém ön thé "
"çürrént zöné. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#"
"Ûsé önlý TÀB änd SHÌFT+TÀB tö nävïgäté ßétwéén dräggäßlé ïtéms änd dröp "
"zönés. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#"
#: public/js/drag_and_drop.js
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid "Press CTRL+M to select a draggable item (effectively picking it up)."
msgstr ""
"Préss ÇTRL+M tö séléçt ä dräggäßlé ïtém (éfféçtïvélý pïçkïng ït üp). Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #"
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ""
"Press \"Esc\" if you want to cancel the drop operation (for example, to "
"Navigate using TAB and SHIFT+TAB to the appropriate dropzone and press "
"CTRL+M once more to drop it here."
msgstr ""
"Nävïgäté üsïng TÀB änd SHÌFT+TÀB tö thé äppröprïäté dröpzöné änd préss "
"ÇTRL+M önçé möré tö dröp ït héré. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#"
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ""
"Press ESC if you want to cancel the drop operation (for example, to "
"select a different item)."
msgstr ""
"Préss \"Ésç\" ïf ýöü wänt tö çänçél thé dröp öpérätïön (för éxämplé, tö "
"Préss ÉSÇ ïf ýöü wänt tö çänçél thé dröp öpérätïön (för éxämplé, tö "
"séléçt ä dïfférént ïtém). Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#"
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid ""
"TAB back to the list of draggable items and repeat this process until all of"
" the draggable items have been placed on their respective dropzones."
msgstr ""
"TÀB ßäçk tö thé lïst öf dräggäßlé ïtéms änd répéät thïs pröçéss üntïl äll öf"
" thé dräggäßlé ïtéms hävé ßéén pläçéd ön théïr réspéçtïvé dröpzönés. Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя "
"ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ "
"ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ "
"¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє "
"¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт "
"ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ є#"
#: public/js/drag_and_drop.js
msgid "OK"
msgstr "ÖK Ⱡ'σя#"
......@@ -641,9 +686,9 @@ msgid_plural "{possible} points possible (ungraded)"
msgstr[0] "{possible} pöïnt pössïßlé (üngrädéd) Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
msgstr[1] "{possible} pöïnts pössïßlé (üngrädéd) Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
#: public/js/drag_and_drop_edit.js
msgid "Close item feedback popup"
msgstr "Çlösé ïtém féédßäçk pöpüp Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
#: drag_and_drop_v2/public/js/drag_and_drop.js
msgid "Close"
msgstr "Çlösé Ⱡ'σяєм ιρѕ#"
#: utils.py:44
msgid "Your highest score is {score}"
......
......@@ -4,6 +4,7 @@
import json
from xml.sax.saxutils import escape
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
......@@ -384,7 +385,7 @@ class InteractionTestBase(object):
self.wait_until_ondrop_xhr_finished(item)
item_content = item.find_element_by_css_selector('.item-content')
self.wait_until_visible(item_content)
item_description = item.find_element_by_css_selector('.sr')
item_description = item.find_element_by_css_selector('.sr.description')
self.wait_until_visible(item_description)
item_description_id = '-item-{}-description'.format(item_value)
......@@ -421,12 +422,13 @@ class InteractionTestBase(object):
self.assertEqual(item.get_attribute('class'), 'option')
self.assertEqual(item.get_attribute('tabindex'), '0')
self.assertEqual(item.get_attribute('aria-grabbed'), 'false')
item_description_id = '-item-{}-description'.format(item_value)
self.assertEqual(item_content.get_attribute('aria-describedby'), item_description_id)
self.assertEqual(item_content.get_attribute('aria-describedby'), None)
describedby_text = (u'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.')
self.assertEqual(item.find_element_by_css_selector('.sr').text, describedby_text)
try:
item.find_element_by_css_selector('.sr.description')
self.fail("Description element exists")
except NoSuchElementException:
pass
def place_decoy_items(self, items_map, action_key):
decoy_items = self._get_items_without_zone(items_map)
......
......@@ -23,6 +23,8 @@ loader = ResourceLoader(__name__)
# Classes ###########################################################
ITEM_DRAG_KEYBOARD_KEYS = (None, Keys.RETURN, Keys.CONTROL+'m')
class ParameterizedTestsMixin(object):
def parameterized_item_positive_feedback_on_good_move(
......@@ -167,7 +169,7 @@ class ParameterizedTestsMixin(object):
self.assertDictEqual(locations_after_reset[item_key], initial_locations[item_key])
self.assert_reverted_item(item_key)
def interact_with_keyboard_help(self, scroll_down=250, use_keyboard=False):
def interact_with_keyboard_help(self, scroll_down=100, use_keyboard=False):
keyboard_help_button = self._get_keyboard_help_button()
keyboard_help_dialog = self._get_keyboard_help_dialog()
dialog_modal_overlay, dialog_modal = self._get_dialog_components(keyboard_help_dialog)
......@@ -211,15 +213,15 @@ class StandardInteractionTest(DefaultDataTestMixin, InteractionTestBase, Paramet
All interactions are tested using mouse (action_key=None) and four different keyboard action keys.
If default data changes this will break.
"""
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_item_positive_feedback_on_good_move(self, action_key):
self.parameterized_item_positive_feedback_on_good_move(self.items_map, action_key=action_key)
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_item_negative_feedback_on_bad_move(self, action_key):
self.parameterized_item_negative_feedback_on_bad_move(self.items_map, self.all_zones, action_key=action_key)
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_cannot_move_items_between_zones(self, action_key):
self.parameterized_cannot_move_items_between_zones(
self.items_map, self.all_zones, action_key=action_key
......@@ -236,9 +238,12 @@ class StandardInteractionTest(DefaultDataTestMixin, InteractionTestBase, Paramet
for _, definition in self.items_map.items():
item = self._get_unplaced_item_by_value(definition.item_id)
ActionChains(self.browser).move_to_element(item).perform()
keyboard_help_text = (u'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.')
self.assertEqual(item.find_element_by_css_selector('.sr').text, keyboard_help_text)
self.assertEqual(item.find_element_by_css_selector('.sr.draggable').text, ", draggable")
item.send_keys("")
item.send_keys(Keys.ENTER) # grabbed an item
self.assertEqual(item.find_element_by_css_selector('.sr.draggable').text, ", draggable, grabbed")
item.send_keys(Keys.ESCAPE)
self.assertEqual(item.find_element_by_css_selector('.sr.draggable').text, ", draggable")
def test_alt_text_for_zones(self):
self._get_popup()
......@@ -264,7 +269,7 @@ class StandardInteractionTest(DefaultDataTestMixin, InteractionTestBase, Paramet
self.wait_until_visible(item_content)
self.assertTrue(item_content.text in zone_description)
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_final_feedback_and_reset(self, action_key):
self.parameterized_final_feedback_and_reset(self.items_map, self.feedback, action_key=action_key)
......@@ -442,21 +447,21 @@ class MultipleBlocksDataInteraction(ParameterizedTestsMixin, InteractionTestBase
self._switch_to_block(0)
self.parameterized_item_positive_feedback_on_good_move(self.item_maps['block1'])
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=1000)
def test_item_negative_feedback_on_bad_move(self):
self._switch_to_block(0)
self.parameterized_item_negative_feedback_on_bad_move(self.item_maps['block1'], self.all_zones['block1'])
self._switch_to_block(1)
self.parameterized_item_negative_feedback_on_bad_move(
self.item_maps['block2'], self.all_zones['block2'], scroll_down=900
self.item_maps['block2'], self.all_zones['block2'], scroll_down=1000
)
def test_final_feedback_and_reset(self):
self._switch_to_block(0)
self.parameterized_final_feedback_and_reset(self.item_maps['block1'], self.feedback['block1'])
self._switch_to_block(1)
self.parameterized_final_feedback_and_reset(self.item_maps['block2'], self.feedback['block2'], scroll_down=900)
self.parameterized_final_feedback_and_reset(self.item_maps['block2'], self.feedback['block2'], scroll_down=1000)
def test_keyboard_help(self):
self._switch_to_block(0)
......@@ -466,7 +471,7 @@ class MultipleBlocksDataInteraction(ParameterizedTestsMixin, InteractionTestBase
self._switch_to_block(1)
# Test mouse and keyboard interaction
self.interact_with_keyboard_help(scroll_down=1200)
self.interact_with_keyboard_help(scroll_down=1000)
self.interact_with_keyboard_help(scroll_down=0, use_keyboard=True)
......@@ -477,7 +482,7 @@ class ZoneAlignInteractionTest(InteractionTestBase, BaseIntegrationTest):
"""
PAGE_TITLE = 'Drag and Drop v2'
PAGE_ID = 'drag_and_drop_v2'
ACTION_KEYS = (None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
ACTION_KEYS = ITEM_DRAG_KEYBOARD_KEYS
def setUp(self):
super(ZoneAlignInteractionTest, self).setUp()
......
......@@ -7,6 +7,7 @@ from mock import Mock, patch
import time
import re
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
......@@ -18,7 +19,9 @@ from drag_and_drop_v2.default_data import (
)
from drag_and_drop_v2.utils import FeedbackMessages, Constants
from .test_base import BaseIntegrationTest
from .test_interaction import InteractionTestBase, DefaultDataTestMixin, ParameterizedTestsMixin, TestMaxItemsPerZone
from .test_interaction import (
InteractionTestBase, DefaultDataTestMixin, ParameterizedTestsMixin, TestMaxItemsPerZone, ITEM_DRAG_KEYBOARD_KEYS
)
# Globals ###########################################################
......@@ -76,25 +79,25 @@ class AssessmentInteractionTest(
All interactions are tested using mouse (action_key=None) and four different keyboard action keys.
If default data changes this will break.
"""
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_item_no_feedback_on_good_move(self, action_key):
self.parameterized_item_positive_feedback_on_good_move(
self.items_map, action_key=action_key, assessment_mode=True
)
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_item_no_feedback_on_bad_move(self, action_key):
self.parameterized_item_negative_feedback_on_bad_move(
self.items_map, self.all_zones, action_key=action_key, assessment_mode=True
)
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_move_items_between_zones(self, action_key):
self.parameterized_move_items_between_zones(
self.items_map, self.all_zones, action_key=action_key
)
@data(None, Keys.RETURN, Keys.SPACE, Keys.CONTROL+'m', Keys.COMMAND+'m')
@data(*ITEM_DRAG_KEYBOARD_KEYS)
def test_final_feedback_and_reset(self, action_key):
self.parameterized_final_feedback_and_reset(
self.items_map, self.feedback, action_key=action_key, assessment_mode=True
......@@ -159,7 +162,7 @@ class AssessmentInteractionTest(
# Incorrect item remains placed
def _assert_placed(item_id, zone_title):
item = self._get_placed_item_by_value(item_id)
item_description = item.find_element_by_css_selector('.sr')
item_description = item.find_element_by_css_selector('.sr.description')
self.assertEqual(item_description.text, 'Placed in: {}'.format(zone_title))
_assert_placed(1, TOP_ZONE_TITLE)
......@@ -204,12 +207,13 @@ class AssessmentInteractionTest(
self.assertEqual(item.get_attribute('class'), 'option fade')
item_content = item.find_element_by_css_selector('.item-content')
item_description_id = '-item-{}-description'.format(item_definition.item_id)
self.assertEqual(item_content.get_attribute('aria-describedby'), item_description_id)
self.assertEqual(item_content.get_attribute('aria-describedby'), None)
describedby_text = (u'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.')
self.assertEqual(item.find_element_by_css_selector('.sr').text, describedby_text)
try:
item.find_element_by_css_selector('.sr.description')
self.fail("Description element should not be present")
except NoSuchElementException:
pass
def test_show_answer(self):
"""
......
......@@ -166,10 +166,7 @@ class TestDragAndDropRender(BaseIntegrationTest):
def test_item_bank(self):
self.load_scenario()
item_bank = self._page.find_element_by_css_selector('.item-bank')
description = item_bank.find_element_by_css_selector('p.zone-description')
self.assertEqual(description.text, 'Item Bank')
# Description should only be visible to screen readers:
self.assertEqual(description.get_attribute('class'), 'zone-description sr')
self.assertEqual(item_bank.get_attribute("aria-label"), 'Item Bank')
def test_zones(self):
self.load_scenario()
......@@ -216,12 +213,10 @@ class TestDragAndDropRender(BaseIntegrationTest):
def test_keyboard_help(self):
self.load_scenario()
keyboard_help_button = self._get_keyboard_help_button()
keyboard_help_dialog = self._get_keyboard_help_dialog()
dialog_modal_overlay = keyboard_help_dialog.find_element_by_css_selector('.modal-window-overlay')
dialog_modal = keyboard_help_dialog.find_element_by_css_selector('.modal-window')
self.assertEqual(keyboard_help_button.get_attribute('tabindex'), '0')
self.assertFalse(dialog_modal_overlay.is_displayed())
self.assertFalse(dialog_modal.is_displayed())
self.assertEqual(dialog_modal.get_attribute('role'), 'dialog')
......
......@@ -14,7 +14,8 @@ disable=
too-few-public-methods,
too-many-public-methods,
invalid-name,
no-member
no-member,
star-args
[SIMILARITIES]
min-similarity-lines=4
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment