[orca] Add support for aria-invalid
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Add support for aria-invalid
- Date: Mon, 24 Oct 2016 19:24:49 +0000 (UTC)
commit 1b2e86f0e364118ddd0ceed5f354209333996744
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Mon Oct 24 15:22:37 2016 -0400
Add support for aria-invalid
src/orca/formatting.py | 42 ++++---
src/orca/generator.py | 19 +++
src/orca/object_properties.py | 42 +++++++-
src/orca/script_utilities.py | 3 +
src/orca/scripts/web/script_utilities.py | 28 +++++
src/orca/speech_generator.py | 10 ++
test/html/aria-invalid.html | 23 ++++
test/keystrokes/firefox/aria_invalid.params | 1 +
test/keystrokes/firefox/aria_invalid.py | 158 +++++++++++++++++++++++++++
9 files changed, 306 insertions(+), 20 deletions(-)
---
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 30e6770..a61fa2a 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -38,6 +38,7 @@ TUTORIAL = '(tutorial and (pause + tutorial) or [])'
MNEMONIC = '(mnemonic and (pause + mnemonic + lineBreak) or [])'
BRAILLE_TEXT = '[Text(obj, asString(labelOrName or placeholderText), asString(eol), startOffset, endOffset)]\
+ + (invalid and [Region(" " + asString(invalid))])\
+ (required and [Region(" " + asString(required))])\
+ (readOnly and [Region(" " + asString(readOnly))])'
@@ -52,6 +53,7 @@ formatting = {
'strings' : {
'speech': {
+ 'invalid': object_properties.INVALID_INDICATORS_SPEECH,
'required': object_properties.STATE_REQUIRED_SPEECH,
'readonly': object_properties.STATE_READ_ONLY_SPEECH,
'insensitive': object_properties.STATE_INSENSITIVE_SPEECH,
@@ -72,6 +74,7 @@ formatting = {
'required': object_properties.STATE_REQUIRED_BRAILLE,
'readonly': object_properties.STATE_READ_ONLY_BRAILLE,
'insensitive': object_properties.STATE_INSENSITIVE_BRAILLE,
+ 'invalid': object_properties.INVALID_INDICATORS_BRAILLE,
'checkbox': object_properties.CHECK_BOX_INDICATORS_BRAILLE,
'radiobutton': object_properties.RADIO_BUTTON_INDICATORS_BRAILLE,
'togglebutton': object_properties.TOGGLE_BUTTON_INDICATORS_BRAILLE,
@@ -80,6 +83,7 @@ formatting = {
'nestinglevel': object_properties.NESTING_LEVEL_BRAILLE,
},
'sound': {
+ 'invalid': object_properties.INVALID_INDICATORS_SOUND,
'required': object_properties.STATE_REQUIRED_SOUND,
'readonly': object_properties.STATE_READ_ONLY_SOUND,
'insensitive': object_properties.STATE_INSENSITIVE_SOUND,
@@ -136,8 +140,8 @@ formatting = {
},
pyatspi.ROLE_CHECK_BOX: {
'focused': 'checkedState',
- 'unfocused': 'labelOrName + roleName + checkedState + required + availability + ' + MNEMONIC + '
+ accelerator',
- 'basicWhereAmI': 'namedContainingPanel + labelOrName + roleName + checkedState + ' + MNEMONIC +
' + accelerator + required'
+ 'unfocused': 'labelOrName + roleName + checkedState + required + pause + invalid + availability
+ ' + MNEMONIC + ' + accelerator',
+ 'basicWhereAmI': 'namedContainingPanel + labelOrName + roleName + checkedState + ' + MNEMONIC +
' + accelerator + required + pause + invalid'
},
pyatspi.ROLE_CHECK_MENU_ITEM: {
'focused': 'checkedState',
@@ -177,9 +181,9 @@ formatting = {
},
pyatspi.ROLE_ENTRY: {
'focused': 'labelOrName + readOnly + textRole + (currentLineText or placeholderText) +
allTextSelection',
- 'unfocused': 'labelOrName + readOnly + textRole + (currentLineText or placeholderText) +
allTextSelection + ' + MNEMONIC,
- 'basicWhereAmI': 'labelOrName + readOnly + textRole + (textContent or placeholderText) +
anyTextSelection + ' + MNEMONIC,
- 'detailedWhereAmI': 'labelOrName + readOnly + textRole + (textContentWithAttributes or
placeholderText) + anyTextSelection + ' + MNEMONIC,
+ 'unfocused': 'labelOrName + readOnly + textRole + (currentLineText or placeholderText) +
allTextSelection + required + pause + invalid + ' + MNEMONIC,
+ 'basicWhereAmI': 'labelOrName + readOnly + textRole + (textContent or placeholderText) +
anyTextSelection + required + pause + invalid + ' + MNEMONIC,
+ 'detailedWhereAmI': 'labelOrName + readOnly + textRole + (textContentWithAttributes or
placeholderText) + anyTextSelection + required + pause + invalid + ' + MNEMONIC,
},
pyatspi.ROLE_FOOTER: {
'unfocused': '(displayedText or name) + roleName',
@@ -361,13 +365,13 @@ formatting = {
},
pyatspi.ROLE_SLIDER: {
'focused': 'value',
- 'unfocused': 'labelOrName + roleName + value + required + availability + ' + MNEMONIC,
- 'basicWhereAmI': 'labelOrName + roleName + value + percentage + ' + MNEMONIC + ' + accelerator +
required'
+ 'unfocused': 'labelOrName + roleName + value + required + pause + invalid + availability + ' +
MNEMONIC,
+ 'basicWhereAmI': 'labelOrName + roleName + value + percentage + ' + MNEMONIC + ' + accelerator +
required + pause + invalid'
},
pyatspi.ROLE_SPIN_BUTTON: {
'focused': 'name',
- 'unfocused': 'labelAndName + allTextSelection + roleName + availability + ' + MNEMONIC + ' +
required',
- 'basicWhereAmI': 'label + roleName + name + allTextSelection + ' + MNEMONIC + ' + accelerator +
required'
+ 'unfocused': 'labelAndName + allTextSelection + roleName + required + pause + invalid +
availability + ' + MNEMONIC,
+ 'basicWhereAmI': 'label + roleName + name + allTextSelection + ' + MNEMONIC + ' + accelerator +
required + pause + invalid'
},
pyatspi.ROLE_SPLIT_PANE: {
'focused': 'value',
@@ -404,7 +408,7 @@ formatting = {
+ cellCheckedState\
+ (realActiveDescendantDisplayedText or imageDescription + image)\
+ (expandableState and (expandableState + numberOfChildren))\
- + required)'
+ + required + pause + invalid)'
},
pyatspi.ROLE_TABLE_ROW: {
'focused': 'expandableState',
@@ -484,9 +488,9 @@ formatting = {
},
'default': {
'focused': '[Component(obj,\
- asString(label + displayedText + value + roleName + required))]',
+ asString(label + displayedText + value + roleName + required +
invalid))]',
'unfocused': '[Component(obj,\
- asString(label + displayedText + value + roleName + required))]',
+ asString(label + displayedText + value + roleName + required +
invalid))]',
},
pyatspi.ROLE_ALERT: {
'unfocused': '((substring and ' + BRAILLE_TEXT + ')\
@@ -668,7 +672,7 @@ formatting = {
#'REAL_ROLE_SCROLL_PANE': 'default'
pyatspi.ROLE_SLIDER: {
'unfocused': '[Component(obj,\
- asString(labelOrName + value + roleName + required))]'
+ asString(labelOrName + value + roleName + required + invalid))]'
},
pyatspi.ROLE_SPIN_BUTTON: {
'unfocused': '[Text(obj, asString(label), asString(eol))]\
@@ -752,7 +756,7 @@ formatting = {
},
pyatspi.ROLE_CHECK_BOX: {
'focused': 'checkedState',
- 'unfocused': 'roleName + checkedState + required + availability',
+ 'unfocused': 'roleName + checkedState + required + invalid + availability',
},
pyatspi.ROLE_CHECK_MENU_ITEM: {
'focused': 'checkedState',
@@ -764,10 +768,10 @@ formatting = {
},
pyatspi.ROLE_DIAL: {
'focused': 'percentage',
- 'unfocused': 'roleName + percentage + required + availability',
+ 'unfocused': 'roleName + percentage + required + invalid + availability',
},
pyatspi.ROLE_ENTRY: {
- 'unfocused': 'roleName + readOnly + required + availability',
+ 'unfocused': 'roleName + readOnly + required + invalid + availability',
},
pyatspi.ROLE_HEADING: {
'focused': 'expandableState',
@@ -819,11 +823,11 @@ formatting = {
},
pyatspi.ROLE_SLIDER: {
'focused': 'percentage',
- 'unfocused': 'roleName + percentage + required + availability',
+ 'unfocused': 'roleName + percentage + required + invalid + availability',
},
pyatspi.ROLE_SPIN_BUTTON: {
'focused': 'percentage',
- 'unfocused': 'roleName + availability + percentage + required',
+ 'unfocused': 'roleName + availability + percentage + required + invalid',
},
pyatspi.ROLE_SPLIT_PANE: {
'focused': 'percentage',
@@ -837,7 +841,7 @@ formatting = {
'focused': 'expandableState',
},
pyatspi.ROLE_TEXT: {
- 'unfocused': 'roleName + readOnly + required + availability',
+ 'unfocused': 'roleName + readOnly + required + invalid + availability',
},
pyatspi.ROLE_TOGGLE_BUTTON: {
'focused': 'expandableState or toggleState',
diff --git a/src/orca/generator.py b/src/orca/generator.py
index 6fb2f7a..2797436 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -462,6 +462,25 @@ class Generator:
result.append(self._script.formatting.getString(**args))
return result
+ def _generateInvalid(self, obj, **args):
+ error = self._script.utilities.getError(obj)
+ if not error:
+ return []
+
+ result = []
+ if not args.get('mode', None):
+ args['mode'] = self._mode
+ args['stringType'] = 'invalid'
+ indicators = self._script.formatting.getString(**args)
+
+ if error == 'spelling':
+ result.append(indicators[1])
+ elif error == 'grammar':
+ result.append(indicators[2])
+ else:
+ result.append(indicators[0])
+ return result
+
def _generateRequired(self, obj, **args):
"""Returns an array of strings for use by speech and braille that
represent the required state of the object, but only if it is
diff --git a/src/orca/object_properties.py b/src/orca/object_properties.py
index 3087d93..a9a11ff 100644
--- a/src/orca/object_properties.py
+++ b/src/orca/object_properties.py
@@ -298,7 +298,39 @@ STATE_REQUIRED_BRAILLE = _("required")
# one item can be selected at a time.
STATE_MULTISELECT_SPEECH = _("multi-select")
-
+# Translators: STATE_INVALID_ENTRY indicates that the associated object, such
+# as a form field, has an error. The following string is spoken when all we
+# know is that an error has occurred, but not the type of error.
+STATE_INVALID_SPEECH = C_("error", "invalid entry")
+
+# Translators: STATE_INVALID_ENTRY indicates that the associated object, such
+# as a form field, has an error. The following string is displayed in braille
+# when all we know is that an error has occurred, but not the type of error.
+# We prefer a smaller string than in speech because braille displays have a
+# limited size.
+STATE_INVALID_BRAILLE = C_("error", "invalid")
+
+# Translators: STATE_INVALID_ENTRY indicates that the associated object, such
+# as a form field, has an error. The following string is spoken when the error
+# is related to spelling.
+STATE_INVALID_SPELLING_SPEECH = C_("error", "invalid spelling")
+
+# Translators: STATE_INVALID_ENTRY indicates that the associated object, such
+# as a form field, has an error. The following string is displayed in braille
+# when the error is related to spelling. We prefer a smaller string than in
+# speech because braille displays have a limited size.
+STATE_INVALID_SPELLING_BRAILLE = C_("error", "spelling")
+
+# Translators: STATE_INVALID_ENTRY indicates that the associated object, such
+# as a form field, has an error. The following string is spoken when the error
+# is related to grammar.
+STATE_INVALID_GRAMMAR_SPEECH = C_("error", "invalid grammar")
+
+# Translators: STATE_INVALID_ENTRY indicates that the associated object, such
+# as a form field, has an error. The following string is displayed in braille
+# when the error is related to grammar. We prefer a smaller string than in
+# speech because braille displays have a limited size.
+STATE_INVALID_GRAMMAR_BRAILLE = C_("error", "grammar")
# TODO: Look at why we're doing this as lists.
@@ -306,6 +338,10 @@ CHECK_BOX_INDICATORS_SPEECH = \
[STATE_NOT_CHECKED, STATE_CHECKED, STATE_PARTIALLY_CHECKED]
EXPANSION_INDICATORS_SPEECH = \
[STATE_COLLAPSED, STATE_EXPANDED]
+INVALID_INDICATORS_SPEECH = \
+ [STATE_INVALID_SPEECH,
+ STATE_INVALID_SPELLING_SPEECH,
+ STATE_INVALID_GRAMMAR_SPEECH]
RADIO_BUTTON_INDICATORS_SPEECH = \
[STATE_UNSELECTED_RADIO_BUTTON, STATE_SELECTED_RADIO_BUTTON]
TOGGLE_BUTTON_INDICATORS_SPEECH = \
@@ -313,6 +349,9 @@ TOGGLE_BUTTON_INDICATORS_SPEECH = \
CHECK_BOX_INDICATORS_BRAILLE = ["< >", "<x>", "<->"]
EXPANSION_INDICATORS_BRAILLE = [STATE_COLLAPSED, STATE_EXPANDED]
+INVALID_INDICATORS_BRAILLE = [STATE_INVALID_BRAILLE,
+ STATE_INVALID_SPELLING_BRAILLE,
+ STATE_INVALID_GRAMMAR_BRAILLE]
RADIO_BUTTON_INDICATORS_BRAILLE = ["& y", "&=y"]
TOGGLE_BUTTON_INDICATORS_BRAILLE = ["& y", "&=y"]
@@ -321,6 +360,7 @@ EOL_INDICATOR_BRAILLE = " $l"
CHECK_BOX_INDICATORS_SOUND = ["not_checked", "checked", "partially_checked"]
EXPANSION_INDICATORS_SOUND = ["collapsed", "expanded"]
+INVALID_INDICATORS_SOUND = ["invalid", "invalid_spelling", "invalid_grammar"]
RADIO_BUTTON_INDICATORS_SOUND = ["unselected", "selected"]
TOGGLE_BUTTON_INDICATORS_SOUND = ["not_pressed", "pressed"]
STATE_CLICKABLE_SOUND = "clickable"
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 529df0b..14b4b07 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -2369,6 +2369,9 @@ class Utilities:
return False
+ def getError(self, obj):
+ return obj.getState().contains(pyatspi.STATE_INVALID_ENTRY)
+
def getCharacterAtOffset(self, obj, offset=None):
text = self.queryNonEmptyText(obj)
if text:
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index b7f9836..bbbe82c 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -2835,6 +2835,34 @@ class Utilities(script_utilities.Utilities):
return child
+ def getError(self, obj):
+ if not (obj and self.inDocumentContent(obj)):
+ return super().getError(obj)
+
+ try:
+ state = obj.getState()
+ except:
+ msg = "ERROR: Exception getting state for %s" % obj
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return False
+
+ if not state.contains(pyatspi.STATE_INVALID_ENTRY):
+ return False
+
+ try:
+ self._currentAttrs.pop(hash(obj))
+ except:
+ pass
+
+ attrs, start, end = self.textAttributes(obj, 0, True)
+ error = attrs.get("invalid")
+ if error == "false":
+ return False
+ if error not in ["spelling", "grammar"]:
+ return True
+
+ return error
+
def hasNoSize(self, obj):
if not (obj and self.inDocumentContent(obj)):
return super().hasNoSize(obj)
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index a019261..39e76f4 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -262,6 +262,16 @@ class SpeechGenerator(generator.Generator):
result.extend(acss)
return result
+ def _generateInvalid(self, obj, **args):
+ if _settingsManager.getSetting('onlySpeakDisplayedText'):
+ return []
+
+ acss = self.voice(SYSTEM)
+ result = generator.Generator._generateInvalid(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
def _generateRequired(self, obj, **args):
if _settingsManager.getSetting('onlySpeakDisplayedText'):
return []
diff --git a/test/html/aria-invalid.html b/test/html/aria-invalid.html
new file mode 100644
index 0000000..3f263d9
--- /dev/null
+++ b/test/html/aria-invalid.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+<title>Invalid</title>
+</head>
+<body>
+<p>Examples:</p>
+<div>
+ <input aria-label="text 1" type="text" value="Hello wurld" aria-invalid="spelling">
+ <input aria-label="text 2" type="text" value="World hello" aria-invalid="grammar">
+ <input aria-label="text 3" type="text" value="1234" aria-invalid="true">
+ <input aria-label="text 4" type="text" value="Good" aria-invalid="false">
+ <input aria-label="accept terms of service" type="checkbox" value="tos-accepted" aria-invalid="true">
+</div>
+<div>
+ <input aria-label="time 1" id="time1" type="text" aria-errormessage="msgID" value="" aria-invalid="false">
+ <span id="msgID" aria-live="off" style="visibility:hidden"> Invalid time: the time must be between 9:00
AM and 5:00 PM" </span>
+</div>
+<div>
+ <input aria-label="time 2" id="time2" type="text" aria-errormessage="msgID" aria-invalid="true"
value="11:30 PM" />
+ <span id="msgID" style="visibility:visible"> Invalid time: The time must be between 9:00 AM and 5:00
PM"</span>
+</div>
+</body>
+</html>
diff --git a/test/keystrokes/firefox/aria_invalid.params b/test/keystrokes/firefox/aria_invalid.params
new file mode 100644
index 0000000..ea699f2
--- /dev/null
+++ b/test/keystrokes/firefox/aria_invalid.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-invalid.html
diff --git a/test/keystrokes/firefox/aria_invalid.py b/test/keystrokes/firefox/aria_invalid.py
new file mode 100644
index 0000000..f94b68c
--- /dev/null
+++ b/test/keystrokes/firefox/aria_invalid.py
@@ -0,0 +1,158 @@
+#!/usr/bin/python
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+#sequence.append(WaitForDocLoad())
+sequence.append(PauseAction(5000))
+sequence.append(KeyComboAction("<Control>Home"))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "1. Tab",
+ ["BRAILLE LINE: 'text 1 Hello wurld $l spelling'",
+ " VISIBLE: 'text 1 Hello wurld $l spelling', cursor=19",
+ "BRAILLE LINE: 'Focus mode'",
+ " VISIBLE: 'Focus mode', cursor=0",
+ "BRAILLE LINE: 'text 1 Hello wurld $l spelling'",
+ " VISIBLE: 'text 1 Hello wurld $l spelling', cursor=19",
+ "SPEECH OUTPUT: 'text 1 entry Hello wurld selected.'",
+ "SPEECH OUTPUT: 'invalid spelling'",
+ "SPEECH OUTPUT: 'Focus mode' voice=system"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "2. WhereAmI",
+ ["BRAILLE LINE: 'text 1 Hello wurld $l spelling'",
+ " VISIBLE: 'text 1 Hello wurld $l spelling', cursor=19",
+ "SPEECH OUTPUT: 'text 1 entry Hello wurld selected.'",
+ "SPEECH OUTPUT: 'invalid spelling'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "3. Tab",
+ ["BRAILLE LINE: 'text 2 World hello $l grammar'",
+ " VISIBLE: 'text 2 World hello $l grammar', cursor=19",
+ "BRAILLE LINE: 'text 2 World hello $l grammar'",
+ " VISIBLE: 'text 2 World hello $l grammar', cursor=19",
+ "SPEECH OUTPUT: 'text 2 entry World hello selected.'",
+ "SPEECH OUTPUT: 'invalid grammar'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "4. WhereAmI",
+ ["BRAILLE LINE: 'text 2 World hello $l grammar'",
+ " VISIBLE: 'text 2 World hello $l grammar', cursor=19",
+ "SPEECH OUTPUT: 'text 2 entry World hello selected.'",
+ "SPEECH OUTPUT: 'invalid grammar'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "5. Tab",
+ ["BRAILLE LINE: 'text 3 1234 $l invalid'",
+ " VISIBLE: 'text 3 1234 $l invalid', cursor=12",
+ "BRAILLE LINE: 'text 3 1234 $l invalid'",
+ " VISIBLE: 'text 3 1234 $l invalid', cursor=12",
+ "SPEECH OUTPUT: 'text 3 entry 1234 selected.'",
+ "SPEECH OUTPUT: 'invalid entry'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "6. WhereAmI",
+ ["BRAILLE LINE: 'text 3 1234 $l invalid'",
+ " VISIBLE: 'text 3 1234 $l invalid', cursor=12",
+ "SPEECH OUTPUT: 'text 3 entry 1234 selected.'",
+ "SPEECH OUTPUT: 'invalid entry'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "7. Tab",
+ ["BRAILLE LINE: 'text 4 Good $l'",
+ " VISIBLE: 'text 4 Good $l', cursor=12",
+ "BRAILLE LINE: 'text 4 Good $l'",
+ " VISIBLE: 'text 4 Good $l', cursor=12",
+ "SPEECH OUTPUT: 'text 4 entry Good selected.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "8. WhereAmI",
+ ["BRAILLE LINE: 'text 4 Good $l'",
+ " VISIBLE: 'text 4 Good $l', cursor=12",
+ "SPEECH OUTPUT: 'text 4 entry Good selected.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "9. Tab",
+ ["BRAILLE LINE: '< > accept terms of service check box'",
+ " VISIBLE: '< > accept terms of service chec', cursor=1",
+ "BRAILLE LINE: 'Browse mode'",
+ " VISIBLE: 'Browse mode', cursor=0",
+ "SPEECH OUTPUT: 'accept terms of service check box not checked.'",
+ "SPEECH OUTPUT: 'invalid entry'",
+ "SPEECH OUTPUT: 'Browse mode' voice=system"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "10. WhereAmI",
+ ["BRAILLE LINE: '< > accept terms of service check box'",
+ " VISIBLE: '< > accept terms of service chec', cursor=1",
+ "BRAILLE LINE: '< > accept terms of service check box'",
+ " VISIBLE: '< > accept terms of service chec', cursor=1",
+ "SPEECH OUTPUT: 'accept terms of service check box not checked.'",
+ "SPEECH OUTPUT: 'invalid entry'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "11. Tab",
+ ["BRAILLE LINE: 'time 1 $l'",
+ " VISIBLE: 'time 1 $l', cursor=8",
+ "BRAILLE LINE: 'Focus mode'",
+ " VISIBLE: 'Focus mode', cursor=0",
+ "SPEECH OUTPUT: 'time 1 entry.'",
+ "SPEECH OUTPUT: 'Focus mode' voice=system"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "12. WhereAmI",
+ ["BRAILLE LINE: 'time 1 $l'",
+ " VISIBLE: 'time 1 $l', cursor=8",
+ "BRAILLE LINE: 'time 1 $l'",
+ " VISIBLE: 'time 1 $l', cursor=8",
+ "SPEECH OUTPUT: 'time 1 entry.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(utils.AssertPresentationAction(
+ "13. Tab",
+ ["BRAILLE LINE: 'time 2 11:30 PM $l invalid'",
+ " VISIBLE: 'time 2 11:30 PM $l invalid', cursor=16",
+ "BRAILLE LINE: 'time 2 11:30 PM $l invalid'",
+ " VISIBLE: 'time 2 11:30 PM $l invalid', cursor=16",
+ "SPEECH OUTPUT: 'time 2 entry 11:30 PM selected.'",
+ "SPEECH OUTPUT: 'invalid entry'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(utils.AssertPresentationAction(
+ "14. WhereAmI",
+ ["BRAILLE LINE: 'time 2 11:30 PM $l invalid'",
+ " VISIBLE: 'time 2 11:30 PM $l invalid', cursor=16",
+ "SPEECH OUTPUT: 'time 2 entry 11:30 PM selected.'",
+ "SPEECH OUTPUT: 'invalid entry'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]