From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- accessible/tests/mochitest/pivot.js | 551 ++++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 accessible/tests/mochitest/pivot.js (limited to 'accessible/tests/mochitest/pivot.js') diff --git a/accessible/tests/mochitest/pivot.js b/accessible/tests/mochitest/pivot.js new file mode 100644 index 000000000..7bb1d81ac --- /dev/null +++ b/accessible/tests/mochitest/pivot.js @@ -0,0 +1,551 @@ +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +//////////////////////////////////////////////////////////////////////////////// +// Constants + +const PREFILTER_INVISIBLE = nsIAccessibleTraversalRule.PREFILTER_INVISIBLE; +const PREFILTER_ARIA_HIDDEN = nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN; +const PREFILTER_TRANSPARENT = nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT; +const FILTER_MATCH = nsIAccessibleTraversalRule.FILTER_MATCH; +const FILTER_IGNORE = nsIAccessibleTraversalRule.FILTER_IGNORE; +const FILTER_IGNORE_SUBTREE = nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE; +const CHAR_BOUNDARY = nsIAccessiblePivot.CHAR_BOUNDARY; +const WORD_BOUNDARY = nsIAccessiblePivot.WORD_BOUNDARY; + +const NS_ERROR_NOT_IN_TREE = 0x80780026; +const NS_ERROR_INVALID_ARG = 0x80070057; + +//////////////////////////////////////////////////////////////////////////////// +// Traversal rules + +/** + * Rule object to traverse all focusable nodes and text nodes. + */ +var HeadersTraversalRule = +{ + getMatchRoles: function(aRules) + { + aRules.value = [ROLE_HEADING]; + return aRules.value.length; + }, + + preFilter: PREFILTER_INVISIBLE, + + match: function(aAccessible) + { + return FILTER_MATCH; + }, + + QueryInterface: XPCOMUtils.generateQI([nsIAccessibleTraversalRule]) +} + +/** + * Traversal rule for all focusable nodes or leafs. + */ +var ObjectTraversalRule = +{ + getMatchRoles: function(aRules) + { + aRules.value = []; + return 0; + }, + + preFilter: PREFILTER_INVISIBLE | PREFILTER_ARIA_HIDDEN | PREFILTER_TRANSPARENT, + + match: function(aAccessible) + { + var rv = FILTER_IGNORE; + var role = aAccessible.role; + if (hasState(aAccessible, STATE_FOCUSABLE) && + (role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME)) + rv = FILTER_IGNORE_SUBTREE | FILTER_MATCH; + else if (aAccessible.childCount == 0 && + role != ROLE_STATICTEXT && aAccessible.name.trim()) + rv = FILTER_MATCH; + + return rv; + }, + + QueryInterface: XPCOMUtils.generateQI([nsIAccessibleTraversalRule]) +}; + +//////////////////////////////////////////////////////////////////////////////// +// Virtual state invokers and checkers + +/** + * A checker for virtual cursor changed events. + */ +function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod, + aIsFromUserInput) +{ + this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc); + + this.match = function VCChangedChecker_match(aEvent) + { + var event = null; + try { + event = aEvent.QueryInterface(nsIAccessibleVirtualCursorChangeEvent); + } catch (e) { + return false; + } + + var expectedReason = VCChangedChecker.methodReasonMap[aPivotMoveMethod] || + nsIAccessiblePivot.REASON_NONE; + + return event.reason == expectedReason; + }; + + this.check = function VCChangedChecker_check(aEvent) + { + SimpleTest.info("VCChangedChecker_check"); + + var event = null; + try { + event = aEvent.QueryInterface(nsIAccessibleVirtualCursorChangeEvent); + } catch (e) { + SimpleTest.ok(false, "Does not support correct interface: " + e); + } + + var position = aDocAcc.virtualCursor.position; + var idMatches = position && position.DOMNode.id == aIdOrNameOrAcc; + var nameMatches = position && position.name == aIdOrNameOrAcc; + var accMatches = position == aIdOrNameOrAcc; + + SimpleTest.ok(idMatches || nameMatches || accMatches, "id or name matches", + "expecting " + aIdOrNameOrAcc + ", got '" + + prettyName(position)); + + SimpleTest.is(aEvent.isFromUserInput, aIsFromUserInput, + "Expected user input is " + aIsFromUserInput + '\n'); + + if (aTextOffsets) { + SimpleTest.is(aDocAcc.virtualCursor.startOffset, aTextOffsets[0], + "wrong start offset"); + SimpleTest.is(aDocAcc.virtualCursor.endOffset, aTextOffsets[1], + "wrong end offset"); + } + + var prevPosAndOffset = VCChangedChecker. + getPreviousPosAndOffset(aDocAcc.virtualCursor); + + if (prevPosAndOffset) { + SimpleTest.is(event.oldAccessible, prevPosAndOffset.position, + "previous position does not match"); + SimpleTest.is(event.oldStartOffset, prevPosAndOffset.startOffset, + "previous start offset does not match"); + SimpleTest.is(event.oldEndOffset, prevPosAndOffset.endOffset, + "previous end offset does not match"); + } + }; +} + +VCChangedChecker.prevPosAndOffset = {}; + +VCChangedChecker.storePreviousPosAndOffset = + function storePreviousPosAndOffset(aPivot) +{ + VCChangedChecker.prevPosAndOffset[aPivot] = + {position: aPivot.position, + startOffset: aPivot.startOffset, + endOffset: aPivot.endOffset}; +}; + +VCChangedChecker.getPreviousPosAndOffset = + function getPreviousPosAndOffset(aPivot) +{ + return VCChangedChecker.prevPosAndOffset[aPivot]; +}; + +VCChangedChecker.methodReasonMap = { + 'moveNext': nsIAccessiblePivot.REASON_NEXT, + 'movePrevious': nsIAccessiblePivot.REASON_PREV, + 'moveFirst': nsIAccessiblePivot.REASON_FIRST, + 'moveLast': nsIAccessiblePivot.REASON_LAST, + 'setTextRange': nsIAccessiblePivot.REASON_TEXT, + 'moveNextByText': nsIAccessiblePivot.REASON_TEXT, + 'movePreviousByText': nsIAccessiblePivot.REASON_TEXT, + 'moveToPoint': nsIAccessiblePivot.REASON_POINT +}; + +/** + * Set a text range in the pivot and wait for virtual cursor change event. + * + * @param aDocAcc [in] document that manages the virtual cursor + * @param aTextAccessible [in] accessible to set to virtual cursor's position + * @param aTextOffsets [in] start and end offsets of text range to set in + * virtual cursor. + */ +function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets) +{ + this.invoke = function virtualCursorChangedInvoker_invoke() + { + VCChangedChecker. + storePreviousPosAndOffset(aDocAcc.virtualCursor); + SimpleTest.info(prettyName(aTextAccessible) + " " + aTextOffsets); + aDocAcc.virtualCursor.setTextRange(aTextAccessible, + aTextOffsets[0], + aTextOffsets[1]); + }; + + this.getID = function setVCRangeInvoker_getID() + { + return "Set offset in " + prettyName(aTextAccessible) + + " to (" + aTextOffsets[0] + ", " + aTextOffsets[1] + ")"; + }; + + this.eventSeq = [ + new VCChangedChecker(aDocAcc, aTextAccessible, aTextOffsets, "setTextRange", true) + ]; +} + +/** + * Move the pivot and wait for virtual cursor change event. + * + * @param aDocAcc [in] document that manages the virtual cursor + * @param aPivotMoveMethod [in] method to test (ie. "moveNext", "moveFirst", etc.) + * @param aRule [in] traversal rule object + * @param aIdOrNameOrAcc [in] id, accessible or accessible name to expect + * virtual cursor to land on after performing move method. + * false if no move is expected. + * @param aIsFromUserInput [in] set user input flag when invoking method, and + * expect it in the event. + */ +function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc, + aIsFromUserInput) +{ + var expectMove = (aIdOrNameOrAcc != false); + this.invoke = function virtualCursorChangedInvoker_invoke() + { + VCChangedChecker. + storePreviousPosAndOffset(aDocAcc.virtualCursor); + if (aPivotMoveMethod && aRule) { + var moved = false; + switch (aPivotMoveMethod) { + case 'moveFirst': + case 'moveLast': + moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule, + aIsFromUserInput === undefined ? true : aIsFromUserInput); + break; + case 'moveNext': + case 'movePrevious': + moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule, + aDocAcc.virtualCursor.position, false, + aIsFromUserInput === undefined ? true : aIsFromUserInput); + break; + } + SimpleTest.is(!!moved, !!expectMove, + "moved pivot with " + aPivotMoveMethod + + " to " + aIdOrNameOrAcc); + } else { + aDocAcc.virtualCursor.position = getAccessible(aIdOrNameOrAcc); + } + }; + + this.getID = function setVCPosInvoker_getID() + { + return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod; + }; + + if (expectMove) { + this.eventSeq = [ + new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, null, aPivotMoveMethod, + aIsFromUserInput === undefined ? !!aPivotMoveMethod : aIsFromUserInput) + ]; + } else { + this.eventSeq = []; + this.unexpectedEventSeq = [ + new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc) + ]; + } +} + +/** + * Move the pivot by text and wait for virtual cursor change event. + * + * @param aDocAcc [in] document that manages the virtual cursor + * @param aPivotMoveMethod [in] method to test (ie. "moveNext", "moveFirst", etc.) + * @param aBoundary [in] boundary constant + * @param aTextOffsets [in] start and end offsets of text range to set in + * virtual cursor. + * @param aIdOrNameOrAcc [in] id, accessible or accessible name to expect + * virtual cursor to land on after performing move method. + * false if no move is expected. + * @param aIsFromUserInput [in] set user input flag when invoking method, and + * expect it in the event. + */ +function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets, + aIdOrNameOrAcc, aIsFromUserInput) +{ + var expectMove = (aIdOrNameOrAcc != false); + this.invoke = function virtualCursorChangedInvoker_invoke() + { + VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor); + SimpleTest.info(aDocAcc.virtualCursor.position); + var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aBoundary, + aIsFromUserInput === undefined ? true : false); + SimpleTest.is(!!moved, !!expectMove, + "moved pivot by text with " + aPivotMoveMethod + + " to " + aIdOrNameOrAcc); + }; + + this.getID = function setVCPosInvoker_getID() + { + return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod + " in " + + prettyName(aIdOrNameOrAcc) + ", " + boundaryToString(aBoundary) + + ", [" + aTextOffsets + "]"; + }; + + if (expectMove) { + this.eventSeq = [ + new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod, + aIsFromUserInput === undefined ? true : aIsFromUserInput) + ]; + } else { + this.eventSeq = []; + this.unexpectedEventSeq = [ + new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc) + ]; + } +} + + +/** + * Move the pivot to the position under the point. + * + * @param aDocAcc [in] document that manages the virtual cursor + * @param aX [in] screen x coordinate + * @param aY [in] screen y coordinate + * @param aIgnoreNoMatch [in] don't unset position if no object was found at + * point. + * @param aRule [in] traversal rule object + * @param aIdOrNameOrAcc [in] id, accessible or accessible name to expect + * virtual cursor to land on after performing move method. + * false if no move is expected. + */ +function moveVCCoordInvoker(aDocAcc, aX, aY, aIgnoreNoMatch, + aRule, aIdOrNameOrAcc) +{ + var expectMove = (aIdOrNameOrAcc != false); + this.invoke = function virtualCursorChangedInvoker_invoke() + { + VCChangedChecker. + storePreviousPosAndOffset(aDocAcc.virtualCursor); + var moved = aDocAcc.virtualCursor.moveToPoint(aRule, aX, aY, + aIgnoreNoMatch); + SimpleTest.ok((expectMove && moved) || (!expectMove && !moved), + "moved pivot"); + }; + + this.getID = function setVCPosInvoker_getID() + { + return "Do " + (expectMove ? "" : "no-op ") + "moveToPoint " + aIdOrNameOrAcc; + }; + + if (expectMove) { + this.eventSeq = [ + new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, null, 'moveToPoint', true) + ]; + } else { + this.eventSeq = []; + this.unexpectedEventSeq = [ + new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc) + ]; + } +} + +/** + * Change the pivot modalRoot + * + * @param aDocAcc [in] document that manages the virtual cursor + * @param aModalRootAcc [in] accessible of the modal root, or null + * @param aExpectedResult [in] error result expected. 0 if expecting success + */ +function setModalRootInvoker(aDocAcc, aModalRootAcc, aExpectedResult) +{ + this.invoke = function setModalRootInvoker_invoke() + { + var errorResult = 0; + try { + aDocAcc.virtualCursor.modalRoot = aModalRootAcc; + } catch (x) { + SimpleTest.ok( + x.result, "Unexpected exception when changing modal root: " + x); + errorResult = x.result; + } + + SimpleTest.is(errorResult, aExpectedResult, + "Did not get expected result when changing modalRoot"); + }; + + this.getID = function setModalRootInvoker_getID() + { + return "Set modalRoot to " + prettyName(aModalRootAcc); + }; + + this.eventSeq = []; + this.unexpectedEventSeq = [ + new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc) + ]; +} + +/** + * Add invokers to a queue to test a rule and an expected sequence of element ids + * or accessible names for that rule in the given document. + * + * @param aQueue [in] event queue in which to push invoker sequence. + * @param aDocAcc [in] the managing document of the virtual cursor we are + * testing + * @param aRule [in] the traversal rule to use in the invokers + * @param aModalRoot [in] a modal root to use in this traversal sequence + * @param aSequence [in] a sequence of accessible names or element ids to expect + * with the given rule in the given document + */ +function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence) +{ + aDocAcc.virtualCursor.position = null; + + // Add modal root (if any) + aQueue.push(new setModalRootInvoker(aDocAcc, aModalRoot, 0)); + + aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0])); + + for (var i = 1; i < aSequence.length; i++) { + var invoker = + new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]); + aQueue.push(invoker); + } + + // No further more matches for given rule, expect no virtual cursor changes. + aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false)); + + for (var i = aSequence.length-2; i >= 0; i--) { + var invoker = + new setVCPosInvoker(aDocAcc, "movePrevious", aRule, aSequence[i]); + aQueue.push(invoker); + } + + // No previous more matches for given rule, expect no virtual cursor changes. + aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false)); + + aQueue.push(new setVCPosInvoker(aDocAcc, "moveLast", aRule, + aSequence[aSequence.length - 1])); + + // No further more matches for given rule, expect no virtual cursor changes. + aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false)); + + // set isFromUserInput to false, just to test.. + aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0], false)); + + // No previous more matches for given rule, expect no virtual cursor changes. + aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false)); + + // Remove modal root (if any). + aQueue.push(new setModalRootInvoker(aDocAcc, null, 0)); +} + +/** + * A checker for removing an accessible while the virtual cursor is on it. + */ +function removeVCPositionChecker(aDocAcc, aHiddenParentAcc) +{ + this.__proto__ = new invokerChecker(EVENT_REORDER, aHiddenParentAcc); + + this.check = function removeVCPositionChecker_check(aEvent) { + var errorResult = 0; + try { + aDocAcc.virtualCursor.moveNext(ObjectTraversalRule); + } catch (x) { + errorResult = x.result; + } + SimpleTest.is( + errorResult, NS_ERROR_NOT_IN_TREE, + "Expecting NOT_IN_TREE error when moving pivot from invalid position."); + }; +} + +/** + * Put the virtual cursor's position on an object, and then remove it. + * + * @param aDocAcc [in] document that manages the virtual cursor + * @param aPosNode [in] DOM node to hide after virtual cursor's position is + * set to it. + */ +function removeVCPositionInvoker(aDocAcc, aPosNode) +{ + this.accessible = getAccessible(aPosNode); + this.invoke = function removeVCPositionInvoker_invoke() + { + aDocAcc.virtualCursor.position = this.accessible; + aPosNode.parentNode.removeChild(aPosNode); + }; + + this.getID = function removeVCPositionInvoker_getID() + { + return "Bring virtual cursor to accessible, and remove its DOM node."; + }; + + this.eventSeq = [ + new removeVCPositionChecker(aDocAcc, this.accessible.parent) + ]; +} + +/** + * A checker for removing the pivot root and then calling moveFirst, and + * checking that an exception is thrown. + */ +function removeVCRootChecker(aPivot) +{ + this.__proto__ = new invokerChecker(EVENT_REORDER, aPivot.root.parent); + + this.check = function removeVCRootChecker_check(aEvent) { + var errorResult = 0; + try { + aPivot.moveLast(ObjectTraversalRule); + } catch (x) { + errorResult = x.result; + } + SimpleTest.is( + errorResult, NS_ERROR_NOT_IN_TREE, + "Expecting NOT_IN_TREE error when moving pivot from invalid position."); + }; +} + +/** + * Create a pivot, remove its root, and perform an operation where the root is + * needed. + * + * @param aRootNode [in] DOM node of which accessible will be the root of the + * pivot. Should have more than one child. + */ +function removeVCRootInvoker(aRootNode) +{ + this.pivot = gAccService.createAccessiblePivot(getAccessible(aRootNode)); + this.invoke = function removeVCRootInvoker_invoke() + { + this.pivot.position = this.pivot.root.firstChild; + aRootNode.parentNode.removeChild(aRootNode); + }; + + this.getID = function removeVCRootInvoker_getID() + { + return "Remove root of pivot from tree."; + }; + + this.eventSeq = [ + new removeVCRootChecker(this.pivot) + ]; +} + +/** + * A debug utility for writing proper sequences for queueTraversalSequence. + */ +function dumpTraversalSequence(aPivot, aRule) +{ + var sequence = []; + if (aPivot.moveFirst(aRule)) { + do { + sequence.push("'" + prettyName(aPivot.position) + "'"); + } while (aPivot.moveNext(aRule)) + } + SimpleTest.info("\n[" + sequence.join(", ") + "]\n"); +} -- cgit v1.2.3