Commit 99929eae by Tim Krones

Add tests for keyboard a11y.

parent 238bbe21
...@@ -14,8 +14,9 @@ TOP_ZONE_DESCRIPTION = _("Use this zone to associate an item with the top layer ...@@ -14,8 +14,9 @@ TOP_ZONE_DESCRIPTION = _("Use this zone to associate an item with the top layer
MIDDLE_ZONE_DESCRIPTION = _("Use this zone to associate an item with the middle layer of the triangle.") MIDDLE_ZONE_DESCRIPTION = _("Use this zone to associate an item with the middle layer of the triangle.")
BOTTOM_ZONE_DESCRIPTION = _("Use this zone to associate an item with the bottom layer of the triangle.") BOTTOM_ZONE_DESCRIPTION = _("Use this zone to associate an item with the bottom layer of the triangle.")
ITEM_INCORRECT_FEEDBACK = _("No, this item does not belong here. Try again.")
ITEM_CORRECT_FEEDBACK = _("Correct! This one belongs to {zone}.") ITEM_CORRECT_FEEDBACK = _("Correct! This one belongs to {zone}.")
ITEM_INCORRECT_FEEDBACK = _("No, this item does not belong here. Try again.")
ITEM_NO_ZONE_FEEDBACK = _("You silly, there are no zones for this one.")
START_FEEDBACK = _("Drag the items onto the image above.") START_FEEDBACK = _("Drag the items onto the image above.")
FINISH_FEEDBACK = _("Good work! You have completed this drag and drop exercise.") FINISH_FEEDBACK = _("Good work! You have completed this drag and drop exercise.")
...@@ -88,7 +89,7 @@ DEFAULT_DATA = { ...@@ -88,7 +89,7 @@ DEFAULT_DATA = {
{ {
"displayName": _("I don't belong anywhere"), "displayName": _("I don't belong anywhere"),
"feedback": { "feedback": {
"incorrect": _("You silly, there are no zones for this one."), "incorrect": ITEM_NO_ZONE_FEEDBACK,
"correct": "" "correct": ""
}, },
"zone": "none", "zone": "none",
......
...@@ -91,7 +91,7 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -91,7 +91,7 @@ function DragAndDropBlock(runtime, element, configuration) {
}; };
var focusModalButton = function() { var focusModalButton = function() {
$root.find('.keyboard-help-dialog .dismiss-modal-button ').focus(); $root.find('.keyboard-help-dialog .modal-dismiss-button ').focus();
}; };
var showKeyboardHelp = function(evt) { var showKeyboardHelp = function(evt) {
...@@ -108,7 +108,7 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -108,7 +108,7 @@ function DragAndDropBlock(runtime, element, configuration) {
// Set up event handlers // Set up event handlers
$(document).on('keydown', keyboardEventDispatcher); $(document).on('keydown', keyboardEventDispatcher);
$keyboardHelpDialog.find('.dismiss-modal-button').on('click', hideKeyboardHelp); $keyboardHelpDialog.find('.modal-dismiss-button').on('click', hideKeyboardHelp);
}; };
var hideKeyboardHelp = function(evt) { var hideKeyboardHelp = function(evt) {
...@@ -124,7 +124,7 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -124,7 +124,7 @@ function DragAndDropBlock(runtime, element, configuration) {
// Remove event handlers // Remove event handlers
$(document).off('keydown', keyboardEventDispatcher); $(document).off('keydown', keyboardEventDispatcher);
$keyboardHelpDialog.find('.dismiss-modal-button').off(); $keyboardHelpDialog.find('.modal-dismiss-button').off();
}; };
/** Asynchronously load the main background image used for this block. */ /** Asynchronously load the main background image used for this block. */
......
...@@ -164,25 +164,27 @@ ...@@ -164,25 +164,27 @@
var dialog_attributes = { role: 'dialog', 'aria-labelledby': 'modal-window-title' }; var dialog_attributes = { role: 'dialog', 'aria-labelledby': 'modal-window-title' };
var dialog_style = {}; var dialog_style = {};
return ( return (
h('div.keyboard-help-dialog', [ h('section.keyboard-help', [
h('div.modal-window-overlay'), h('a.keyboard-help-button', { attributes: { tabindex: 0 } }, gettext('Keyboard Help')),
h('div.modal-window', { attributes: dialog_attributes, style: dialog_style }, [ h('div.keyboard-help-dialog', [
h('div.modal-header', [ h('div.modal-window-overlay'),
h('h2.modal-window-title', gettext('Keyboard Help')) h('div.modal-window', { attributes: dialog_attributes, style: dialog_style }, [
]), h('div.modal-header', [
h('div.modal-content', [ h('h2.modal-window-title', gettext('Keyboard Help'))
h('p', gettext('You can complete this exercise using only your keyboard.')), ]),
h('ul', [ h('div.modal-content', [
h('li', gettext('Use "Tab" and "Shift-Tab" to navigate between items and zones.')), h('p', gettext('You can complete this exercise using only your keyboard.')),
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('ul', [
h('li', gettext('Press "Enter" or "Space" to drop the item on the current zone.')), h('li', gettext('Use "Tab" and "Shift-Tab" to navigate between items and zones.')),
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 "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 "?" at any time to bring up this dialog.')), h('li', gettext('Press "Enter" or "Space" 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 "?" at any time to bring up this dialog.')),
])
]),
h('div.modal-actions', [
h('button.modal-dismiss-button', gettext("OK"))
]) ])
]),
h('div.modal-actions', [
h('h3.sr', gettext('Actions')),
h('button.dismiss-modal-button', gettext("OK"))
]) ])
]) ])
]) ])
...@@ -223,9 +225,6 @@ ...@@ -223,9 +225,6 @@
renderCollection(itemTemplate, items_placed, ctx), renderCollection(itemTemplate, items_placed, ctx),
]), ]),
]), ]),
h('section.keyboard-help', [
h('a.keyboard-help-button', { attributes: { tabindex: 0 } }, gettext('Keyboard Help'))
]),
keyboardHelpTemplate(ctx), keyboardHelpTemplate(ctx),
feedbackTemplate(ctx), feedbackTemplate(ctx),
]) ])
......
...@@ -57,6 +57,21 @@ class BaseIntegrationTest(SeleniumBaseTest): ...@@ -57,6 +57,21 @@ class BaseIntegrationTest(SeleniumBaseTest):
def _get_zones(self): def _get_zones(self):
return self._page.find_elements_by_css_selector(".drag-container .zone") return self._page.find_elements_by_css_selector(".drag-container .zone")
def _get_popup(self):
return self._page.find_element_by_css_selector(".popup")
def _get_popup_content(self):
return self._page.find_element_by_css_selector(".popup .popup-content")
def _get_keyboard_help(self):
return self._page.find_element_by_css_selector(".keyboard-help")
def _get_keyboard_help_button(self):
return self._page.find_element_by_css_selector(".keyboard-help .keyboard-help-button")
def _get_keyboard_help_dialog(self):
return self._page.find_element_by_css_selector(".keyboard-help .keyboard-help-dialog")
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")
......
from ddt import ddt, data
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver import ActionChains from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from drag_and_drop_v2.default_data import START_FEEDBACK, FINISH_FEEDBACK from drag_and_drop_v2.default_data import (
TOP_ZONE_TITLE, MIDDLE_ZONE_TITLE, BOTTOM_ZONE_TITLE,
ITEM_CORRECT_FEEDBACK, ITEM_INCORRECT_FEEDBACK, ITEM_NO_ZONE_FEEDBACK,
START_FEEDBACK, FINISH_FEEDBACK
)
from .test_base import BaseIntegrationTest from .test_base import BaseIntegrationTest
from ..utils import load_resource from ..utils import load_resource
ZONES_MAP = {
0: TOP_ZONE_TITLE,
1: MIDDLE_ZONE_TITLE,
2: BOTTOM_ZONE_TITLE,
}
class ItemDefinition(object): class ItemDefinition(object):
def __init__(self, item_id, zone_id, feedback_positive, feedback_negative, input_value=None): def __init__(self, item_id, zone_id, feedback_positive, feedback_negative, input_value=None):
self.feedback_negative = feedback_negative self.feedback_negative = feedback_negative
...@@ -37,6 +52,10 @@ class InteractionTestBase(object): ...@@ -37,6 +52,10 @@ class InteractionTestBase(object):
items_container = self._page.find_element_by_css_selector('.item-bank') items_container = self._page.find_element_by_css_selector('.item-bank')
return items_container.find_elements_by_xpath("//div[@data-value='{item_id}']".format(item_id=item_value))[0] return items_container.find_elements_by_xpath("//div[@data-value='{item_id}']".format(item_id=item_value))[0]
def _get_placed_item_by_value(self, item_value):
items_container = self._page.find_element_by_css_selector('.target')
return items_container.find_elements_by_xpath("//div[@data-value='{item_id}']".format(item_id=item_value))[0]
def _get_zone_by_id(self, zone_id): def _get_zone_by_id(self, zone_id):
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-zone='{zone_id}']".format(zone_id=zone_id))[0] return zones_container.find_elements_by_xpath("//div[@data-zone='{zone_id}']".format(zone_id=zone_id))[0]
...@@ -63,28 +82,98 @@ class InteractionTestBase(object): ...@@ -63,28 +82,98 @@ class InteractionTestBase(object):
action_chains = ActionChains(self.browser) action_chains = ActionChains(self.browser)
action_chains.drag_and_drop(element, target).perform() action_chains.drag_and_drop(element, target).perform()
def parameterized_item_positive_feedback_on_good_move(self, items_map, scroll_down=100): def move_item_to_zone(self, item_value, zone_id, action_key):
# Get item position
item_position = item_value
# Get zone position
zone_position = self.get_zone_position(zone_id)
self.focus_item(0)
focused_item = self._get_item_by_value(0)
for i in range(item_position):
focused_item.send_keys(Keys.TAB)
focused_item = self._get_item_by_value(i+1)
focused_item.send_keys(action_key) # Focus is on first *zone* now
focused_zone = self._get_zone_by_id(ZONES_MAP[0])
for i in range(zone_position):
focused_zone.send_keys(Keys.TAB)
focused_zone = self._get_zone_by_id(ZONES_MAP[i+1])
focused_zone.send_keys(action_key)
def get_zone_position(self, zone_id):
return self.browser.execute_script(
'return $("div[data-zone=\'{zone_id}\']").prevAll(".zone").length'.format(zone_id=zone_id)
)
def focus_item(self, item_position):
self.browser.execute_script("$('.option:nth-child({n})').focus()".format(n=item_position+1))
def assert_placed_item(self, item_value, zone_id):
item = self._get_placed_item_by_value(item_value)
item_content = item.find_element_by_css_selector('.item-content')
item_description = item.find_element_by_css_selector('.sr')
item_description_id = 'item-{}-description'.format(item_value)
self.assertIsNone(item.get_attribute('tabindex'))
self.assertEqual(item.get_attribute('aria-grabbed'), 'false')
self.assertEqual(item.get_attribute('data-drag-disabled'), 'true')
self.assertEqual(item_content.get_attribute('aria-describedby'), item_description_id)
self.assertEqual(item_description.get_attribute('id'), item_description_id)
self.assertEqual(item_description.text, 'Correctly placed in: {}'.format(zone_id))
def assert_reverted_item(self, item_value):
item = self._get_item_by_value(item_value)
item_content = item.find_element_by_css_selector('.item-content')
self.assertEqual(item.get_attribute('tabindex'), '0')
self.assertEqual(item.get_attribute('draggable'), 'true')
self.assertEqual(item.get_attribute('aria-grabbed'), 'false')
self.assertEqual(item.get_attribute('data-drag-disabled'), 'false')
self.assertIsNone(item_content.get_attribute('aria-describedby'))
try:
item.find_element_by_css_selector('.sr')
except NoSuchElementException:
pass
else:
self.fail('Reverted item should not have .sr description.')
def parameterized_item_positive_feedback_on_good_move(
self, items_map, scroll_down=100, use_keyboard=False, action_key=Keys.RETURN
):
# 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_correct_item_for_zone(items_map).values():
if not definition.input: if not definition.input:
self.drag_item_to_zone(definition.item_id, definition.zone_id) if use_keyboard:
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)
feedback_popup = self.get_feedback_popup() feedback_popup = self.get_feedback_popup()
self.wait_until_html_in(definition.feedback_positive, feedback_popup) self.wait_until_html_in(definition.feedback_positive, feedback_popup)
self.assert_placed_item(definition.item_id, definition.zone_id)
def parameterized_item_positive_feedback_on_good_input(self, items_map, scroll_down=100): def parameterized_item_positive_feedback_on_good_input(
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 = self.get_feedback_popup()
for definition in self._get_correct_item_for_zone(items_map).values(): for definition in self._get_correct_item_for_zone(items_map).values():
if definition.input: if definition.input:
self.drag_item_to_zone(definition.item_id, definition.zone_id) if use_keyboard:
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)
self._send_input(definition.item_id, definition.input) 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)
self.assert_placed_item(definition.item_id, definition.zone_id)
def parameterized_item_negative_feedback_on_bad_move(self, items_map, all_zones, scroll_down=100): def parameterized_item_negative_feedback_on_bad_move(
self, items_map, all_zones, scroll_down=100, use_keyboard=False, action_key=Keys.RETURN
):
feedback_popup = self.get_feedback_popup() 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
...@@ -94,10 +183,16 @@ class InteractionTestBase(object): ...@@ -94,10 +183,16 @@ 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
self.drag_item_to_zone(definition.item_id, zone) if use_keyboard:
self.move_item_to_zone(definition.item_id, zone, action_key)
else:
self.drag_item_to_zone(definition.item_id, zone)
self.wait_until_html_in(definition.feedback_negative, feedback_popup) self.wait_until_html_in(definition.feedback_negative, feedback_popup)
self.assert_reverted_item(definition.item_id)
def parameterized_item_positive_feedback_on_bad_input(self, items_map, scroll_down=100): def parameterized_item_negative_feedback_on_bad_input(
self, items_map, scroll_down=100, use_keyboard=False, action_key=Keys.RETURN
):
feedback_popup = self.get_feedback_popup() 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
...@@ -105,13 +200,19 @@ class InteractionTestBase(object): ...@@ -105,13 +200,19 @@ class InteractionTestBase(object):
for definition in self._get_correct_item_for_zone(items_map).values(): for definition in self._get_correct_item_for_zone(items_map).values():
if definition.input: if definition.input:
self.drag_item_to_zone(definition.item_id, definition.zone_id) if use_keyboard:
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)
self._send_input(definition.item_id, '1999999') 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)
self.assert_placed_item(definition.item_id, definition.zone_id)
def parameterized_final_feedback_and_reset(self, items_map, feedback, scroll_down=100): def parameterized_final_feedback_and_reset(
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
...@@ -126,11 +227,15 @@ class InteractionTestBase(object): ...@@ -126,11 +227,15 @@ 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():
self.drag_item_to_zone(item_key, definition.zone_id) if use_keyboard:
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.wait_until_html_in(feedback['final'], self._get_feedback_message()) self.wait_until_html_in(feedback['final'], self._get_feedback_message())
...@@ -138,29 +243,66 @@ class InteractionTestBase(object): ...@@ -138,29 +243,66 @@ class InteractionTestBase(object):
self.scroll_down(pixels=scroll_down+150) self.scroll_down(pixels=scroll_down+150)
reset = self.get_reset_button() reset = self.get_reset_button()
reset.click() if use_keyboard:
reset.send_keys(Keys.RETURN)
else:
reset.click()
self.wait_until_html_in(feedback['intro'], self._get_feedback_message()) self.wait_until_html_in(feedback['intro'], self._get_feedback_message())
locations_after_reset = get_locations() locations_after_reset = get_locations()
for item_key in items.keys(): for item_key in items.keys():
self.assertDictEqual(locations_after_reset[item_key], initial_locations[item_key]) 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):
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')
dialog_dismiss_button = dialog_modal.find_element_by_css_selector('.modal-dismiss-button')
# Scroll "Keyboard help" button into view to make sure Selenium can successfully click it
self.scroll_down(pixels=scroll_down)
if use_keyboard:
keyboard_help_button.send_keys(Keys.RETURN)
else:
keyboard_help_button.click()
self.assertTrue(dialog_modal_overlay.is_displayed())
self.assertTrue(dialog_modal.is_displayed())
if use_keyboard:
dialog_dismiss_button.send_keys(Keys.RETURN)
else:
dialog_dismiss_button.click()
self.assertFalse(dialog_modal_overlay.is_displayed())
self.assertFalse(dialog_modal.is_displayed())
class BasicInteractionTest(InteractionTestBase): class BasicInteractionTest(InteractionTestBase):
""" """
Verifying Drag and Drop XBlock rendering against default data - if default data changes this will probably break. Testing interactions with Drag and Drop XBlock against default data. If default data changes this will break.
""" """
PAGE_TITLE = 'Drag and Drop v2' PAGE_TITLE = 'Drag and Drop v2'
PAGE_ID = 'drag_and_drop_v2' PAGE_ID = 'drag_and_drop_v2'
items_map = { items_map = {
0: ItemDefinition(0, 'Zone 1', "Yes, it's a 1", "No, 1 does not belong here"), 0: ItemDefinition(
1: ItemDefinition(1, 'Zone 2', "Yes, it's a 2", "No, 2 does not belong here"), 0, TOP_ZONE_TITLE, ITEM_CORRECT_FEEDBACK.format(zone=TOP_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
2: ItemDefinition(2, None, "", "You silly, there are no zones for X") ),
1: ItemDefinition(
1, MIDDLE_ZONE_TITLE, ITEM_CORRECT_FEEDBACK.format(zone=MIDDLE_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
),
2: ItemDefinition(
2, BOTTOM_ZONE_TITLE, ITEM_CORRECT_FEEDBACK.format(zone=BOTTOM_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
),
3: ItemDefinition(3, None, "", ITEM_NO_ZONE_FEEDBACK),
} }
all_zones = ['Zone 1', 'Zone 2'] all_zones = [TOP_ZONE_TITLE, MIDDLE_ZONE_TITLE, BOTTOM_ZONE_TITLE]
feedback = { feedback = {
"intro": START_FEEDBACK, "intro": START_FEEDBACK,
...@@ -179,12 +321,51 @@ class BasicInteractionTest(InteractionTestBase): ...@@ -179,12 +321,51 @@ class BasicInteractionTest(InteractionTestBase):
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_positive_feedback_on_bad_input(self): def test_item_negative_feedback_on_bad_input(self):
self.parameterized_item_positive_feedback_on_bad_input(self.items_map) 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)
def test_keyboard_help(self):
self.interact_with_keyboard_help()
@ddt
class KeyboardInteractionTest(BasicInteractionTest, BaseIntegrationTest):
@data(Keys.RETURN, Keys.SPACE)
def test_item_positive_feedback_on_good_move(self, action_key):
self.parameterized_item_positive_feedback_on_good_move(
self.items_map, use_keyboard=True, action_key=action_key
)
@data(Keys.RETURN, Keys.SPACE)
def test_item_positive_feedback_on_good_input(self, action_key):
self.parameterized_item_positive_feedback_on_good_input(
self.items_map, use_keyboard=True, action_key=action_key
)
@data(Keys.RETURN, Keys.SPACE)
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, use_keyboard=True, action_key=action_key
)
@data(Keys.RETURN, Keys.SPACE)
def test_item_negative_feedback_on_bad_input(self, action_key):
self.parameterized_item_negative_feedback_on_bad_input(
self.items_map, use_keyboard=True, action_key=action_key
)
@data(Keys.RETURN, Keys.SPACE)
def test_final_feedback_and_reset(self, action_key):
self.parameterized_final_feedback_and_reset(
self.items_map, self.feedback, use_keyboard=True, action_key=action_key
)
def test_keyboard_help(self, use_keyboard=True):
self.interact_with_keyboard_help()
class CustomDataInteractionTest(BasicInteractionTest, BaseIntegrationTest): class CustomDataInteractionTest(BasicInteractionTest, BaseIntegrationTest):
items_map = { items_map = {
...@@ -284,11 +465,11 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest): ...@@ -284,11 +465,11 @@ 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_positive_feedback_on_bad_input(self): def test_item_negative_feedback_on_bad_input(self):
self._switch_to_block(0) self._switch_to_block(0)
self.parameterized_item_positive_feedback_on_bad_input(self.item_maps['block1']) self.parameterized_item_negative_feedback_on_bad_input(self.item_maps['block1'])
self._switch_to_block(1) self._switch_to_block(1)
self.parameterized_item_positive_feedback_on_bad_input(self.item_maps['block2'], scroll_down=900) 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)
......
...@@ -179,6 +179,30 @@ class TestDragAndDropRender(BaseIntegrationTest): ...@@ -179,6 +179,30 @@ class TestDragAndDropRender(BaseIntegrationTest):
# Zone description should only be visible to screen readers: # Zone description should only be visible to screen readers:
self.assertEqual(zone_description.get_attribute('class'), 'zone-description sr') self.assertEqual(zone_description.get_attribute('class'), 'zone-description sr')
def test_popup(self):
self.load_scenario()
popup = self._get_popup()
popup_content = self._get_popup_content()
self.assertFalse(popup.is_displayed())
self.assertEqual(popup.get_attribute('aria-live'), 'polite')
self.assertEqual(popup_content.text, "")
def test_keyboard_help(self):
self.load_scenario()
self._get_keyboard_help()
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')
self.assertEqual(dialog_modal.get_attribute('aria-labelledby'), 'modal-window-title')
def test_feedback(self): def test_feedback(self):
self.load_scenario() self.load_scenario()
......
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