diff options
Diffstat (limited to 'accessible/tests/mochitest/jsat')
23 files changed, 5487 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/jsat/a11y.ini b/accessible/tests/mochitest/jsat/a11y.ini new file mode 100644 index 000000000..5acc3df90 --- /dev/null +++ b/accessible/tests/mochitest/jsat/a11y.ini @@ -0,0 +1,30 @@ +[DEFAULT] +support-files = + dom_helper.js + gestures.json + jsatcommon.js + output.js + doc_traversal.html + doc_content_integration.html + doc_content_text.html + !/accessible/tests/mochitest/*.js + !/accessible/tests/mochitest/moz.png +skip-if = (os == 'win' && (os_version == '5.1' || os_version == '5.2')) + +[test_alive.html] +[test_content_integration.html] +skip-if = buildapp == 'mulet' +[test_content_text.html] +skip-if = buildapp == 'mulet' +[test_explicit_names.html] +[test_gesture_tracker.html] +[test_hints.html] +[test_landmarks.html] +[test_live_regions.html] +[test_output_mathml.html] +[test_output.html] +[test_quicknav_modes.html] +[test_tables.html] +[test_pointer_relay.html] +[test_traversal.html] +[test_traversal_helper.html] diff --git a/accessible/tests/mochitest/jsat/doc_content_integration.html b/accessible/tests/mochitest/jsat/doc_content_integration.html new file mode 100644 index 000000000..d62c000cb --- /dev/null +++ b/accessible/tests/mochitest/jsat/doc_content_integration.html @@ -0,0 +1,115 @@ +<!DOCTYPE html> +<html> +<head> + <title>Traversal Rule test document</title> + <meta charset="utf-8" /> + <script> + var frameContents = '<html>' + + '<head><title>such app</title></head>' + + '<body>' + + '<h1>wow</h1>' + + '<ul>' + + '<li><label><input type="checkbox">many option</label></li>' + + '</ul>' + + '<label for="r">much range</label>' + + '<input min="0" max="10" value="5" type="range" id="r">' + + '</body>' + + '</html>'; + + function showAlert() { + document.getElementById('alert').hidden = false; + } + + function hideAlert() { + document.getElementById('alert').hidden = true; + } + + function ariaShowBack() { + document.getElementById('back').setAttribute('aria-hidden', false); + } + + function ariaHideBack() { + document.getElementById('back').setAttribute('aria-hidden', true); + } + + function ariaShowIframe() { + document.getElementById('iframe').setAttribute('aria-hidden', false); + } + + function ariaHideIframe() { + document.getElementById('iframe').setAttribute('aria-hidden', true); + } + + function renameFruit() { + document.getElementById('fruit').setAttribute('aria-label', 'banana'); + } + + function renameSlider() { + document.getElementById('slider').setAttribute( + 'aria-label', 'mover'); + } + + function changeSliderValue() { + document.getElementById('slider').setAttribute('aria-valuenow', '5'); + document.getElementById('slider').setAttribute( + 'aria-valuetext', 'medium'); + } + + function toggleLight() { + var lightSwitch = document.getElementById('light'); + lightSwitch.setAttribute('aria-checked', + lightSwitch.getAttribute('aria-checked') === 'true' ? 'false' : 'true'); + } + + </script> + <style> + #windows { + position: relative; + width: 320px; + height: 480px; + } + + #windows > iframe { + z-index: 1; + } + + #windows > div[role='dialog'] { + z-index: 2; + background-color: pink; + } + + #windows > * { + position: absolute; + width: 100%; + height: 100%; + } + + iframe { + width: 100%; + height: 100%; + } + + </style> + +</head> +<body> + <div>Phone status bar</div> + <div id="windows"> + <button id="back">Back</button> + <div role="dialog" id="alert" hidden> + <h1>This is an alert!</h1> + <p>Do you agree?</p> + <button onclick="setTimeout(hideAlert, 500)">Yes</button> + <button onclick="hideAlert()">No</button> + </div> + <div id="appframe"></div> + </div> + <button id="home">Home</button> + <button id="fruit" aria-label="apple"></button> + <span id="light" role="switch" aria-label="Light" aria-checked="false" onclick="toggleLight()"></span> + <div id="live" aria-live="polite" aria-label="live"> + <div id="slider" role="slider" aria-label="slider" aria-valuemin="0" + aria-valuemax="10" aria-valuenow="0"></div> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/doc_content_text.html b/accessible/tests/mochitest/jsat/doc_content_text.html new file mode 100644 index 000000000..4e73dc6e7 --- /dev/null +++ b/accessible/tests/mochitest/jsat/doc_content_text.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> + <head> + <title>Text content test document</title> + <meta charset="utf-8" /> + </head> + <body> + <p>These are my awards, Mother. From Army. + The seal is for marksmanship, and the gorilla is for sand racing.</p> + <p>You're a good guy, mon frere. That means brother in French. + I don't know how I know that. I took four years of Spanish.</p> + <textarea>Please refrain from Mayoneggs during this salmonella scare.</textarea> + <label>So we don't get dessert?</label><input type="text"> + </body> +</html>
\ No newline at end of file diff --git a/accessible/tests/mochitest/jsat/doc_traversal.html b/accessible/tests/mochitest/jsat/doc_traversal.html new file mode 100644 index 000000000..4c104b6b7 --- /dev/null +++ b/accessible/tests/mochitest/jsat/doc_traversal.html @@ -0,0 +1,164 @@ +<!DOCTYPE html> +<html> +<head> + <title>Traversal Rule test document</title> + <meta charset="utf-8" /> + <style> + .content:before { + content: "Content"; + } + </style> +</head> +<body> + <header id="header-1"> + <h3 id="heading-1">A small first heading</h3> + <form> + <label for="input-1-1">Name:</label> + <input id="input-1-1"> + <label id="label-1-2">Favourite Ice Cream Flavour:<input id="input-1-2"></label> + <button id="button-1-1">Magic Button</button> + <label for="radio-1-1">Radios are old: </label> + <input id="radio-1-1" type="radio"> + <label for="radio-1-2">Radios are new: </label> + <input id="radio-1-2" type="radio"> + <label for="input-1-3">Password:</label> + <input id="input-1-3" type="password"> + <label for="input-1-4">Unlucky number:</label> + <input id="input-1-4" type="tel"> + <input id="button-1-2" type="button" value="Fun"> + <label for="checkbox-1-1">Check me: </label> + <input id="checkbox-1-1" type="checkbox"> + <select id="select-1-1"> + <option>Value 1</option> + <option>Value 2</option> + <option>Value 3</option> + </select> + <select id="select-1-2" multiple="true"> + <option>Value 1</option> + <option>Value 2</option> + <option>Value 3</option> + </select> + <label for="checkbox-1-2">Check me too: </label> + <input id="checkbox-1-2" type="checkbox"> + <label for="checkbox-1-3">But not me: </label> + <input id="checkbox-1-3" type="checkbox" aria-hidden="true"> + <label for="checkbox-1-4">Or me! </label> + <input id="checkbox-1-4" type="checkbox" style="visibility:hidden"> + <select id="select-1-3" size="3"> + <option>Value 1</option> + <option>Value 2</option> + <option>Value 3</option> + </select> + <label for="input-1-5">Electronic mailing address:</label> + <input id="input-1-5" type="email"> + <input id="button-1-3" type="submit" value="Submit"> + </form> + </header> + <main id="main-1"> + <h2 id="heading-2">A larger second</h2> + <div id="heading-3" role="heading">ARIA is fun</div> + <input id="button-2-1" type="button" value="More Fun"> + <div id="button-2-2" tabindex="0" role="button">ARIA fun</div> + <div id="button-2-3" tabindex="0" role="button" aria-pressed="false">My little togglebutton</div> + <div id="button-2-4" tabindex="0" role="spinbutton">ARIA fun</div> + </main> + <h1 id="heading-4" style="display:none">Invisible header</h1> + <dl id="list-1"> + <dt id="listitem-1-1">Programming Language</dt> + <dd>A esoteric weapon wielded by only the most formidable warriors, + for its unrelenting strict power is unfathomable.</dd> + </dl> + <ul id="list-2" onclick="alert('hi');"> + <li id="listitem-2-1">Lists of Programming Languages</li> + <li id="listitem-2-2">Lisp + <ol id="list-3"> + <li id="listitem-3-1">Scheme</li> + <li id="listitem-3-2">Racket</li> + <li id="listitem-3-3">Clojure</li> + <li id="listitem-3-4"><strong>Standard</strong> Lisp</li> + <li id="listitem-3-5"><a id="link-0" href="#">Common</a> Lisp</li> + <li id="listitem-3-6"><input id="checkbox-1-5" type="checkbox"> LeLisp</li> + </ol> + </li> + <li id="listitem-2-3">JavaScript</li> + </ul> + <section> + <h6 id="heading-5">The last (visible) one!</h6> + <img id="image-1" src="http://example.com" alt=""> + <img id="image-2" src="../moz.png" alt="stuff"> + <div id="image-3" tabindex="0" role="img">Not actually an image</div> + </section> + <section> + <h4 id="heading-6" aria-hidden="true">Hidden header</h4> + <a id="link-1" href="http://www.mozilla.org">Link</a> + <a id="anchor-1">Words</a> + <a id="link-2" href="http://www.mozilla.org">Link the second</a> + <a id="anchor-2">Sentences</a> + <a id="link-3" href="http://www.example.com">Link the third</a> + </section> + <hr id="separator-1"> + <h6 id="heading-6"></h6> + <table id="table-1"> + <tr> + <td>3</td> + <td>1</td> + </tr> + <tr> + <td>4</td> + <td>1</td> + </tr> + </table> + <section id="grid" role="grid"> + <ol role="row"> + <li role="presentation"></li> + <li role="columnheader" aria-label="Sunday">S</li> + <li role="columnheader">M</li> + </ol> + <ol role="row"> + <li role="rowheader" aria-label="Week 1">1</li> + <li role="gridcell"><span>3</span><div></div></li> + <li role="gridcell"><span>4</span><div>7</div></li> + </ol> + <ol role="row"> + <li role="rowheader">2</li> + <li role="gridcell"><span>5</span><div role="presentation">8</div></li> + <li id="gridcell4" role="gridcell"> + <span>6</span><div aria-hidden="true"><div class="content"></div></div> + </li> + </ol> + </section> + <div id="separator-2" role="separator">Just an innocuous separator</div> + <table id="table-2"> + <thead> + <tr> + <th>Dirty Words</th> + <th>Meaning</th> + </tr> + </thead> + <tfoot> + <tr> + <td>Mud</td> + <td>Wet Dirt</td> + </tr> + </tfoot> + <tbody> + <tr> + <td>Dirt</td> + <td>Messy Stuff</td> + </tr> + </tbody> + </table> + <footer id="footer-1"> + <div id="statusbar-1" role="status">Last sync:<span>2 days ago</span></div> + <div aria-label="Last sync: 30min ago" id="statusbar-2" role="status"></div> + </footer> + + <span id="switch-1" role="switch" aria-checked="false" aria-label="Light switch"></span> + <p>This is a MathML formula <math id="math-1" display="block"> + <mfrac> + <mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow> + <msqrt><mn>3</mn><mo>/</mo><mn>4</mn></msqrt> + </mfrac> + </math> with some text after.</p> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/dom_helper.js b/accessible/tests/mochitest/jsat/dom_helper.js new file mode 100644 index 000000000..c95d19dc1 --- /dev/null +++ b/accessible/tests/mochitest/jsat/dom_helper.js @@ -0,0 +1,209 @@ +'use strict'; + +/* global getMainChromeWindow, AccessFuTest, GestureSettings, GestureTracker, + SimpleTest, getBoundsForDOMElm, Point, Utils */ +/* exported loadJSON, eventMap */ + +var Ci = Components.interfaces; +var Cu = Components.utils; + +Cu.import('resource://gre/modules/Geometry.jsm'); + +var win = getMainChromeWindow(window); + +/** + * Convert inch based point coordinates into pixels. + * @param {Array} aPoints Array of coordinates in inches. + * @return {Array} Array of coordinates in pixels. + */ +function convertPointCoordinates(aPoints) { + var dpi = Utils.dpi; + return aPoints.map(function convert(aPoint) { + return { + x: aPoint.x * dpi, + y: aPoint.y * dpi, + identifier: aPoint.identifier + }; + }); +} + +/** + * For a given list of points calculate their coordinates in relation to the + * document body. + * @param {Array} aTouchPoints An array of objects of the following format: { + * base: {String}, // Id of an element to server as a base for the touch. + * x: {Number}, // An optional x offset from the base element's geometric + * // centre. + * y: {Number} // An optional y offset from the base element's geometric + * // centre. + * } + * @return {JSON} An array of {x, y} coordinations. + */ +function calculateTouchListCoordinates(aTouchPoints) { + var coords = []; + for (var i = 0, target = aTouchPoints[i]; i < aTouchPoints.length; ++i) { + var bounds = getBoundsForDOMElm(target.base); + var parentBounds = getBoundsForDOMElm('root'); + var point = new Point(target.x || 0, target.y || 0); + point.scale(Utils.dpi); + point.add(bounds[0], bounds[1]); + point.add(bounds[2] / 2, bounds[3] / 2); + point.subtract(parentBounds[0], parentBounds[0]); + coords.push({ + x: point.x, + y: point.y + }); + } + return coords; +} + +/** + * Send a touch event with specified touchPoints. + * @param {Array} aTouchPoints An array of points to be associated with + * touches. + * @param {String} aName A name of the touch event. + */ +function sendTouchEvent(aTouchPoints, aName) { + var touchList = sendTouchEvent.touchList; + if (aName === 'touchend') { + sendTouchEvent.touchList = null; + } else { + var coords = calculateTouchListCoordinates(aTouchPoints); + var touches = []; + for (var i = 0; i < coords.length; ++i) { + var {x, y} = coords[i]; + var node = document.elementFromPoint(x, y); + var touch = document.createTouch(window, node, aName === 'touchstart' ? + 1 : touchList.item(i).identifier, x, y, x, y); + touches.push(touch); + } + touchList = document.createTouchList(touches); + sendTouchEvent.touchList = touchList; + } + var evt = document.createEvent('TouchEvent'); + evt.initTouchEvent(aName, true, true, window, 0, false, false, false, false, + touchList, touchList, touchList); + document.dispatchEvent(evt); +} + +sendTouchEvent.touchList = null; + +/** + * A map of event names to the functions that actually send them. + * @type {Object} + */ +var eventMap = { + touchstart: sendTouchEvent, + touchend: sendTouchEvent, + touchmove: sendTouchEvent +}; + +/** + * Attach a listener for the mozAccessFuGesture event that tests its + * type. + * @param {Array} aExpectedGestures A stack of expected event types. + * @param {String} aTitle Title of this sequence, if any. + * Note: the listener is removed once the stack reaches 0. + */ +function testMozAccessFuGesture(aExpectedGestures, aTitle) { + var types = aExpectedGestures; + function handleGesture(aEvent) { + if (aEvent.detail.type !== types[0].type) { + info('Got ' + aEvent.detail.type + ' waiting for ' + types[0].type); + // The is not the event of interest. + return; + } + is(!!aEvent.detail.edge, !!types[0].edge); + is(aEvent.detail.touches.length, types[0].fingers || 1, + 'failed to count fingers: ' + types[0].type); + ok(true, 'Received correct mozAccessFuGesture: ' + + JSON.stringify(types.shift()) + '. (' + aTitle + ')'); + if (types.length === 0) { + win.removeEventListener('mozAccessFuGesture', handleGesture); + if (AccessFuTest.sequenceCleanup) { + AccessFuTest.sequenceCleanup(); + } + AccessFuTest.nextTest(); + } + } + win.addEventListener('mozAccessFuGesture', handleGesture); +} + +/** + * Reset the thresholds and max delays that affect gesture rejection. + * @param {Number} aTimeStamp Gesture time stamp. + * @param {Boolean} aRemoveDwellThreshold An optional flag to reset dwell + * threshold. + * @param {Boolean} aRemoveSwipeMaxDuration An optional flag to reset swipe max + * duration. + */ +function setTimers(aTimeStamp, aRemoveDwellThreshold, aRemoveSwipeMaxDuration) { + if (!aRemoveDwellThreshold && !aRemoveSwipeMaxDuration) { + return; + } + if (aRemoveDwellThreshold) { + GestureSettings.dwellThreshold = 0; + } + if (aRemoveSwipeMaxDuration) { + GestureSettings.swipeMaxDuration = 0; + } + GestureTracker.current.clearTimer(); + GestureTracker.current.startTimer(aTimeStamp); +} + +function resetTimers(aRemoveGestureResolveDelay) { + GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold; + GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration; + GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ? + 0 : AccessFuTest.maxGestureResolveTimeout; +} + +/** + * An extention to AccessFuTest that adds an ability to test a sequence of + * pointer events and their expected mozAccessFuGesture events. + * @param {Object} aSequence An object that has a list of pointer events to be + * generated and the expected mozAccessFuGesture events. + */ +AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) { + AccessFuTest.addFunc(function testSequence() { + testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title); + var events = aSequence.events; + function fireEvent(aEvent) { + var event = { + points: convertPointCoordinates(aEvent.points), + type: aEvent.type + }; + var timeStamp = Date.now(); + resetTimers(aEvent.removeGestureResolveDelay); + GestureTracker.handle(event, timeStamp); + setTimers(timeStamp, aEvent.removeDwellThreshold, + aEvent.removeSwipeMaxDuration); + processEvents(); + } + function processEvents() { + if (events.length === 0) { + return; + } + var event = events.shift(); + SimpleTest.executeSoon(function() { + fireEvent(event); + }); + } + processEvents(); + }); +}; + +/** + * A helper function that loads JSON files. + * @param {String} aPath A path to a JSON file. + * @param {Function} aCallback A callback to be called on success. + */ +function loadJSON(aPath, aCallback) { + var request = new XMLHttpRequest(); + request.open('GET', aPath, true); + request.responseType = 'json'; + request.onload = function onload() { + aCallback(request.response); + }; + request.send(); +} diff --git a/accessible/tests/mochitest/jsat/gestures.json b/accessible/tests/mochitest/jsat/gestures.json new file mode 100644 index 000000000..111994342 --- /dev/null +++ b/accessible/tests/mochitest/jsat/gestures.json @@ -0,0 +1,352 @@ +[ + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "tap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.03, "y": 1.03, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "tap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "dwellend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]}, + {"type": "pointerup", + "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]}, + {"type": "pointerup", + "points": [{"x": 0.97, "y": 1.01, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "doubletap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "tripletap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "doubletaphold" }, + { "type": "doubletapholdend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "taphold" }, { "type": "tapholdend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swiperight" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1.15, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1.3, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.3, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swiperight" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeleft" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1.5, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipedown" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeup" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swiperight" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 0.95, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 0.95, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeleft" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 0.9, "y": 1.5, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 0.9, "y": 1.5, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipedown" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.1, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeup" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]} + ], + "expectedGestures": [{ "type": "swiperight", "fingers": 2 }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1.5, "identifier": 2}]} + ], + "expectedGestures": [{ "type": "swiperight", "fingers": 2 }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}, + {"x": 1, "y": 2, "identifier": 3}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}, + {"x": 1.5, "y": 2, "identifier": 3}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}, + {"x": 1.5, "y": 2, "identifier": 3}]} + ], + "expectedGestures": [{ "type": "swiperight", "fingers": 3 }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "explore" }, + { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 2, "y": 2, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 2, "y": 2, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "explore" }, + { "type": "explore" }, { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeSwipeMaxDuration": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "explore" }, { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeSwipeMaxDuration": true}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "explore" }, { "type": "explore" }, + { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointermove", + "points": [{"x": 1.5, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.55, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.65, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.7, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.75, "y": 1.5, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.75, "y": 1.5, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "explore" }, + { "type": "explore" }, { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 0.075, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]} + ], + "expectedGestures": [{ "type": "swiperight", "edge": true, "fingers": 2 }] + }, + { + "title": "Bug 1182311 - 3 finger triple tap is not reliable 1/2", + "events": [ + {"points": [ + {"y": 1.88467, "x": 0.89311, "identifier": 0}, + {"y": 2.78481, "x": 0.56259, "identifier": 1}, + {"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerdown"}, + {"points": [ + {"y": 1.88467, "x": 0.89311, "identifier": 0}, + {"y": 2.78481, "x": 0.56259, "identifier": 1}, + {"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerup"}, + {"points": [ + {"y": 1.76512, "x": 0.98453, "identifier": 0}, + {"y": 1.1744, "x": 1.4346, "identifier": 1}, + {"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerdown"}, + {"points": [ + {"y": 1.76512, "x": 0.98453, "identifier": 0}, + {"y": 1.1744, "x": 1.4346, "identifier": 1}, + {"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerup"}, + {"points": [ + {"y": 1.30098, "x": 1.52602, "identifier": 0}, + {"y": 1.94093, "x": 1.02672, "identifier": 1}, + {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerdown"}, + {"points": [ + {"y": 1.30098, "x": 1.52602, "identifier": 0}, + {"y": 1.94093, "x": 1.02672, "identifier": 1}, + {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup", + "removeGestureResolveDelay": true}], + "expectedGestures": [{ "type": "tripletap", "fingers": 3 }] + }, + { + "title": "Bug 1182311 - 3 finger triple tap is not reliable 2/2", + "events": [ + {"type": "pointerdown", + "points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]}, + {"type": "pointerdown", + "points": [{"identifier": 1, "x": 1.479167, "y": 2.53125}]}, + {"type": "pointerdown", + "points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]}, + {"type": "pointermove", + "points": [{"identifier": 1, "x": 1.46875, "y": 2.53125}]}, + {"type": "pointermove", + "points": [{"identifier": 1, "x": 1.447917, "y": 2.46875}]}, + {"type": "pointerup", + "points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]}, + {"type": "pointerup", + "points": [{"identifier": 1, "x": 1.447917, "y": 2.489583}]}, + {"type": "pointerup", + "points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]}, + {"type": "pointerdown", + "points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]}, + {"type": "pointerdown", + "points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]}, + {"type": "pointerdown", + "points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]}, + {"type": "pointermove", + "points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]}, + {"type": "pointermove", + "points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]}, + {"type": "pointerup", + "points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]}, + {"type": "pointerup", + "points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]}, + {"type": "pointerup", + "points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]}, + {"type": "pointerdown", + "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}]}, + {"type": "pointerdown", + "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]}, + {"type": "pointerdown", + "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}]}, + {"type": "pointermove", + "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}, + {"identifier": 2, "x": 2.15625, "y": 1.489583}]}, + {"type": "pointermove", + "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}, + {"identifier": 2, "x": 2.15625, "y": 1.489583}]}, + {"type": "pointerup", + "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}], + "removeGestureResolveDelay": true} + ], + "expectedGestures": [{ "type": "tripletap", "fingers": 3 }] + } + +] diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js new file mode 100644 index 000000000..aa7ee74e4 --- /dev/null +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -0,0 +1,739 @@ +// A common module to run tests on the AccessFu module + +'use strict'; + +/*global isDeeply, getMainChromeWindow, SimpleTest, SpecialPowers, Logger, + AccessFu, Utils, addMessageListener, currentTabDocument, currentBrowser*/ + +/** + * A global variable holding an array of test functions. + */ +var gTestFuncs = []; +/** + * A global Iterator for the array of test functions. + */ +var gIterator; + +Components.utils.import('resource://gre/modules/Services.jsm'); +Components.utils.import("resource://gre/modules/accessibility/Utils.jsm"); +Components.utils.import("resource://gre/modules/accessibility/EventManager.jsm"); +Components.utils.import("resource://gre/modules/accessibility/Gestures.jsm"); + +var AccessFuTest = { + + addFunc: function AccessFuTest_addFunc(aFunc) { + if (aFunc) { + gTestFuncs.push(aFunc); + } + }, + + _registerListener: function AccessFuTest__registerListener(aWaitForMessage, aListenerFunc) { + var listener = { + observe: function observe(aMessage) { + // Ignore unexpected messages. + if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) { + return; + } + if (aMessage.message.indexOf(aWaitForMessage) < 0) { + return; + } + aListenerFunc.apply(listener); + } + }; + Services.console.registerListener(listener); + return listener; + }, + + on_log: function AccessFuTest_on_log(aWaitForMessage, aListenerFunc) { + return this._registerListener(aWaitForMessage, aListenerFunc); + }, + + off_log: function AccessFuTest_off_log(aListener) { + Services.console.unregisterListener(aListener); + }, + + once_log: function AccessFuTest_once_log(aWaitForMessage, aListenerFunc) { + return this._registerListener(aWaitForMessage, + function listenAndUnregister() { + Services.console.unregisterListener(this); + aListenerFunc(); + }); + }, + + _addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) { + var listener = function listener(aSubject, aTopic, aData) { + var data = JSON.parse(aData)[1]; + // Ignore non-relevant outputs. + if (!data) { + return; + } + isDeeply(data.details, aWaitForData, "Data is correct"); + aListener.apply(listener); + }; + Services.obs.addObserver(listener, 'accessibility-output', false); + return listener; + }, + + on: function AccessFuTest_on(aWaitForData, aListener) { + return this._addObserver(aWaitForData, aListener); + }, + + off: function AccessFuTest_off(aListener) { + Services.obs.removeObserver(aListener, 'accessibility-output'); + }, + + once: function AccessFuTest_once(aWaitForData, aListener) { + return this._addObserver(aWaitForData, function observerAndRemove() { + Services.obs.removeObserver(this, 'accessibility-output'); + aListener(); + }); + }, + + _waitForExplicitFinish: false, + + waitForExplicitFinish: function AccessFuTest_waitForExplicitFinish() { + this._waitForExplicitFinish = true; + }, + + finish: function AccessFuTest_finish() { + // Disable the console service logging. + Logger.test = false; + Logger.logLevel = Logger.INFO; + // Reset Gesture Settings. + GestureSettings.dwellThreshold = this.dwellThreshold = + this.originalDwellThreshold; + GestureSettings.swipeMaxDuration = this.swipeMaxDuration = + this.originalSwipeMaxDuration; + GestureSettings.maxGestureResolveTimeout = + this.maxGestureResolveTimeout = + this.originalMaxGestureResolveTimeout; + // Finish through idle callback to let AccessFu._disable complete. + SimpleTest.executeSoon(function () { + AccessFu.detach(); + SimpleTest.finish(); + }); + }, + + nextTest: function AccessFuTest_nextTest() { + var result = gIterator.next(); + if (result.done) { + this.finish(); + return; + } + var testFunc = result.value; + testFunc(); + }, + + runTests: function AccessFuTest_runTests(aAdditionalPrefs) { + if (gTestFuncs.length === 0) { + ok(false, "No tests specified!"); + SimpleTest.finish(); + return; + } + + // Create an Iterator for gTestFuncs array. + gIterator = (function*() { + for (var testFunc of gTestFuncs) { + yield testFunc; + } + })(); + + // Start AccessFu and put it in stand-by. + Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm"); + + AccessFu.attach(getMainChromeWindow(window)); + + AccessFu.readyCallback = function readyCallback() { + // Enable logging to the console service. + Logger.test = true; + Logger.logLevel = Logger.DEBUG; + }; + + var prefs = [['accessibility.accessfu.notify_output', 1], + ['dom.mozSettings.enabled', true]]; + prefs.push.apply(prefs, aAdditionalPrefs); + + this.originalDwellThreshold = GestureSettings.dwellThreshold; + this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration; + this.originalMaxGestureResolveTimeout = + GestureSettings.maxGestureResolveTimeout; + // https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes + // SimpleTest.executeSoon timeout is bigger than the timer settings in + // GestureSettings that causes intermittents. + this.dwellThreshold = GestureSettings.dwellThreshold = + GestureSettings.dwellThreshold * 10; + this.swipeMaxDuration = GestureSettings.swipeMaxDuration = + GestureSettings.swipeMaxDuration * 10; + this.maxGestureResolveTimeout = GestureSettings.maxGestureResolveTimeout = + GestureSettings.maxGestureResolveTimeout * 10; + + SpecialPowers.pushPrefEnv({ 'set': prefs }, function () { + if (AccessFuTest._waitForExplicitFinish) { + // Run all test functions asynchronously. + AccessFuTest.nextTest(); + } else { + // Run all test functions synchronously. + gTestFuncs.forEach(testFunc => testFunc()); + AccessFuTest.finish(); + } + }); + } +}; + +function AccessFuContentTest(aFuncResultPairs) { + this.queue = aFuncResultPairs; +} + +AccessFuContentTest.prototype = { + expected: [], + currentAction: null, + actionNum: -1, + + start: function(aFinishedCallback) { + Logger.logLevel = Logger.DEBUG; + this.finishedCallback = aFinishedCallback; + var self = this; + + // Get top content message manager, and set it up. + this.mms = [Utils.getMessageManager(currentBrowser())]; + this.setupMessageManager(this.mms[0], function () { + // Get child message managers and set them up + var frames = currentTabDocument().querySelectorAll('iframe'); + if (frames.length === 0) { + self.pump(); + return; + } + + var toSetup = 0; + for (var i = 0; i < frames.length; i++ ) { + var mm = Utils.getMessageManager(frames[i]); + if (mm) { + toSetup++; + self.mms.push(mm); + self.setupMessageManager(mm, function () { + if (--toSetup === 0) { + // All message managers are loaded and ready to go. + self.pump(); + } + }); + } + } + }); + }, + + finish: function() { + Logger.logLevel = Logger.INFO; + for (var mm of this.mms) { + mm.sendAsyncMessage('AccessFu:Stop'); + mm.removeMessageListener('AccessFu:Present', this); + mm.removeMessageListener('AccessFu:Input', this); + mm.removeMessageListener('AccessFu:CursorCleared', this); + mm.removeMessageListener('AccessFu:Focused', this); + mm.removeMessageListener('AccessFu:AriaHidden', this); + mm.removeMessageListener('AccessFu:Ready', this); + mm.removeMessageListener('AccessFu:ContentStarted', this); + } + if (this.finishedCallback) { + this.finishedCallback(); + } + }, + + setupMessageManager: function (aMessageManager, aCallback) { + function contentScript() { + addMessageListener('AccessFuTest:Focus', function (aMessage) { + var elem = content.document.querySelector(aMessage.json.selector); + if (elem) { + if (aMessage.json.blur) { + elem.blur(); + } else { + elem.focus(); + } + } + }); + } + + aMessageManager.addMessageListener('AccessFu:Present', this); + aMessageManager.addMessageListener('AccessFu:Input', this); + aMessageManager.addMessageListener('AccessFu:CursorCleared', this); + aMessageManager.addMessageListener('AccessFu:Focused', this); + aMessageManager.addMessageListener('AccessFu:AriaHidden', this); + aMessageManager.addMessageListener('AccessFu:Ready', function () { + aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback); + aMessageManager.sendAsyncMessage('AccessFu:Start', + { buildApp: 'browser', + androidSdkVersion: Utils.AndroidSdkVersion, + logLevel: 'DEBUG', + inTest: true }); + }); + + aMessageManager.loadFrameScript( + 'chrome://global/content/accessibility/content-script.js', false); + aMessageManager.loadFrameScript( + 'data:,(' + contentScript.toString() + ')();', false); + }, + + pump: function() { + this.expected.shift(); + if (this.expected.length) { + return; + } + + var currentPair = this.queue.shift(); + + if (currentPair) { + this.actionNum++; + this.currentAction = currentPair[0]; + if (typeof this.currentAction === 'function') { + this.currentAction(this.mms[0]); + } else if (this.currentAction) { + this.mms[0].sendAsyncMessage(this.currentAction.name, + this.currentAction.json); + } + + this.expected = currentPair.slice(1, currentPair.length); + + if (!this.expected[0]) { + this.pump(); + } + } else { + this.finish(); + } + }, + + receiveMessage: function(aMessage) { + var expected = this.expected[0]; + + if (!expected) { + return; + } + + var actionsString = typeof this.currentAction === 'function' ? + this.currentAction.name + '()' : JSON.stringify(this.currentAction); + + if (typeof expected === 'string') { + ok(true, 'Got ' + expected + ' after ' + actionsString); + this.pump(); + } else if (expected.ignore && !expected.ignore(aMessage)) { + expected.is(aMessage.json, 'after ' + actionsString + + ' (' + this.actionNum + ')'); + expected.is_correct_focus(); + this.pump(); + } + } +}; + +// Common content messages + +var ContentMessages = { + simpleMoveFirst: { + name: 'AccessFu:MoveCursor', + json: { + action: 'moveFirst', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + simpleMoveLast: { + name: 'AccessFu:MoveCursor', + json: { + action: 'moveLast', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + simpleMoveNext: { + name: 'AccessFu:MoveCursor', + json: { + action: 'moveNext', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + simpleMovePrevious: { + name: 'AccessFu:MoveCursor', + json: { + action: 'movePrevious', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + clearCursor: { + name: 'AccessFu:ClearCursor', + json: { + origin: 'top' + } + }, + + moveOrAdjustUp: function moveOrAdjustUp(aRule) { + return { + name: 'AccessFu:MoveCursor', + json: { + origin: 'top', + action: 'movePrevious', + inputType: 'gesture', + rule: (aRule || 'Simple'), + adjustRange: true + } + } + }, + + moveOrAdjustDown: function moveOrAdjustUp(aRule) { + return { + name: 'AccessFu:MoveCursor', + json: { + origin: 'top', + action: 'moveNext', + inputType: 'gesture', + rule: (aRule || 'Simple'), + adjustRange: true + } + } + }, + + androidScrollForward: function adjustUp() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'forward' } + }; + }, + + androidScrollBackward: function adjustDown() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'backward' } + }; + }, + + focusSelector: function focusSelector(aSelector, aBlur) { + return { + name: 'AccessFuTest:Focus', + json: { + selector: aSelector, + blur: aBlur + } + }; + }, + + activateCurrent: function activateCurrent(aOffset) { + return { + name: 'AccessFu:Activate', + json: { + origin: 'top', + offset: aOffset + } + }; + }, + + moveNextBy: function moveNextBy(aGranularity) { + return { + name: 'AccessFu:MoveByGranularity', + json: { + direction: 'Next', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + movePreviousBy: function movePreviousBy(aGranularity) { + return { + name: 'AccessFu:MoveByGranularity', + json: { + direction: 'Previous', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + moveCaretNextBy: function moveCaretNextBy(aGranularity) { + return { + name: 'AccessFu:MoveCaret', + json: { + direction: 'Next', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + moveCaretPreviousBy: function moveCaretPreviousBy(aGranularity) { + return { + name: 'AccessFu:MoveCaret', + json: { + direction: 'Previous', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + _granularityMap: { + 'character': 1, // MOVEMENT_GRANULARITY_CHARACTER + 'word': 2, // MOVEMENT_GRANULARITY_WORD + 'paragraph': 8 // MOVEMENT_GRANULARITY_PARAGRAPH + } +}; + +function ExpectedMessage (aName, aOptions) { + this.name = aName; + this.options = aOptions || {}; + this.json = {}; +} + +ExpectedMessage.prototype.lazyCompare = function(aReceived, aExpected, aInfo) { + if (aExpected && !aReceived) { + return [false, 'Expected something but got nothing -- ' + aInfo]; + } + + var matches = true; + var delta = []; + for (var attr in aExpected) { + var expected = aExpected[attr]; + var received = aReceived[attr]; + if (typeof expected === 'object') { + var [childMatches, childDelta] = this.lazyCompare(received, expected); + if (!childMatches) { + delta.push(attr + ' [ ' + childDelta + ' ]'); + matches = false; + } + } else { + if (received !== expected) { + delta.push( + attr + ' [ expected ' + JSON.stringify(expected) + + ' got ' + JSON.stringify(received) + ' ]'); + matches = false; + } + } + } + + var msg = delta.length ? delta.join(' ') : 'Structures lazily match'; + return [matches, msg + ' -- ' + aInfo]; +}; + +ExpectedMessage.prototype.is = function(aReceived, aInfo) { + var checkFunc = this.options.todo ? 'todo' : 'ok'; + SimpleTest[checkFunc].apply( + SimpleTest, this.lazyCompare(aReceived, this.json, aInfo)); +}; + +ExpectedMessage.prototype.is_correct_focus = function(aInfo) { + if (!this.options.focused) { + return; + } + + var checkFunc = this.options.focused_todo ? 'todo_is' : 'is'; + var doc = currentTabDocument(); + SimpleTest[checkFunc].apply(SimpleTest, + [ doc.activeElement, doc.querySelector(this.options.focused), + 'Correct element is focused: ' + this.options.focused + ' -- ' + aInfo ]); +}; + +ExpectedMessage.prototype.ignore = function(aMessage) { + return aMessage.name !== this.name; +}; + +function ExpectedPresent(aB2g, aAndroid, aOptions) { + ExpectedMessage.call(this, 'AccessFu:Present', aOptions); + if (aB2g) { + this.json.b2g = aB2g; + } + + if (aAndroid) { + this.json.android = aAndroid; + } +} + +ExpectedPresent.prototype = Object.create(ExpectedMessage.prototype); + +ExpectedPresent.prototype.is = function(aReceived, aInfo) { + var received = this.extract_presenters(aReceived); + + for (var presenter of ['b2g', 'android']) { + if (!this.options['no_' + presenter]) { + var todo = this.options.todo || this.options[presenter + '_todo'] + SimpleTest[todo ? 'todo' : 'ok'].apply( + SimpleTest, this.lazyCompare(received[presenter], + this.json[presenter], aInfo + ' (' + presenter + ')')); + } + } +}; + +ExpectedPresent.prototype.extract_presenters = function(aReceived) { + var received = { count: 0 }; + for (var presenter of aReceived) { + if (presenter) { + received[presenter.type.toLowerCase()] = presenter.details; + received.count++; + } + } + + return received +}; + +ExpectedPresent.prototype.ignore = function(aMessage) { + if (ExpectedMessage.prototype.ignore.call(this, aMessage)) { + return true; + } + + var received = this.extract_presenters(aMessage.json); + return received.count === 0 || + (received.visual && received.visual.eventType === 'viewport-change') || + (received.android && + received.android[0].eventType === AndroidEvent.VIEW_SCROLLED); +}; + +function ExpectedCursorChange(aSpeech, aOptions) { + ExpectedPresent.call(this, { + eventType: 'vc-change', + data: aSpeech + }, [{ + eventType: 0x8000, // VIEW_ACCESSIBILITY_FOCUSED + }], aOptions); +} + +ExpectedCursorChange.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedCursorTextChange(aSpeech, aStartOffset, aEndOffset, aOptions) { + ExpectedPresent.call(this, { + eventType: 'vc-change', + data: aSpeech + }, [{ + eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + fromIndex: aStartOffset, + toIndex: aEndOffset + }], aOptions); + + // bug 980509 + this.options.b2g_todo = true; +} + +ExpectedCursorTextChange.prototype = + Object.create(ExpectedCursorChange.prototype); + +function ExpectedClickAction(aOptions) { + ExpectedPresent.call(this, { + eventType: 'action', + data: [{ string: 'clickAction' }] + }, [{ + eventType: AndroidEvent.VIEW_CLICKED + }], aOptions); +} + +ExpectedClickAction.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedCheckAction(aChecked, aOptions) { + ExpectedPresent.call(this, { + eventType: 'action', + data: [{ string: aChecked ? 'checkAction' : 'uncheckAction' }] + }, [{ + eventType: AndroidEvent.VIEW_CLICKED, + checked: aChecked + }], aOptions); +} + +ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedSwitchAction(aSwitched, aOptions) { + ExpectedPresent.call(this, { + eventType: 'action', + data: [{ string: aSwitched ? 'onAction' : 'offAction' }] + }, [{ + eventType: AndroidEvent.VIEW_CLICKED, + checked: aSwitched + }], aOptions); +} + +ExpectedSwitchAction.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedNameChange(aName, aOptions) { + ExpectedPresent.call(this, { + eventType: 'name-change', + data: aName + }, null, aOptions); +} + +ExpectedNameChange.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedValueChange(aValue, aOptions) { + ExpectedPresent.call(this, { + eventType: 'value-change', + data: aValue + }, null, aOptions); +} + +ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedTextChanged(aValue, aOptions) { + ExpectedPresent.call(this, { + eventType: 'text-change', + data: aValue + }, null, aOptions); +} + +ExpectedTextChanged.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedEditState(aEditState, aOptions) { + ExpectedMessage.call(this, 'AccessFu:Input', aOptions); + this.json = aEditState; +} + +ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype); + +function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) { + ExpectedPresent.call(this, null, [{ + eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED, + brailleOutput: { + selectionStart: aStart, + selectionEnd: aEnd + }}], aOptions); +} + +ExpectedTextSelectionChanged.prototype = + Object.create(ExpectedPresent.prototype); + +function ExpectedTextCaretChanged(aFrom, aTo, aOptions) { + ExpectedPresent.call(this, null, [{ + eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + fromIndex: aFrom, + toIndex: aTo + }], aOptions); +} + +ExpectedTextCaretChanged.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedAnnouncement(aAnnouncement, aOptions) { + ExpectedPresent.call(this, null, [{ + eventType: AndroidEvent.ANNOUNCEMENT, + text: [ aAnnouncement], + addedCount: aAnnouncement.length + }], aOptions); +} + +ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedNoMove(aOptions) { + ExpectedPresent.call(this, {eventType: 'no-move' }, null, aOptions); +} + +ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype); + +var AndroidEvent = { + VIEW_CLICKED: 0x01, + VIEW_LONG_CLICKED: 0x02, + VIEW_SELECTED: 0x04, + VIEW_FOCUSED: 0x08, + VIEW_TEXT_CHANGED: 0x10, + WINDOW_STATE_CHANGED: 0x20, + VIEW_HOVER_ENTER: 0x80, + VIEW_HOVER_EXIT: 0x100, + VIEW_SCROLLED: 0x1000, + VIEW_TEXT_SELECTION_CHANGED: 0x2000, + ANNOUNCEMENT: 0x4000, + VIEW_ACCESSIBILITY_FOCUSED: 0x8000, + VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000 +}; diff --git a/accessible/tests/mochitest/jsat/output.js b/accessible/tests/mochitest/jsat/output.js new file mode 100644 index 000000000..5afcc8a66 --- /dev/null +++ b/accessible/tests/mochitest/jsat/output.js @@ -0,0 +1,114 @@ +var Cu = Components.utils; +const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance"; + +Cu.import('resource://gre/modules/accessibility/Utils.jsm'); +Cu.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this); + +/** + * Test context output generation. + * + * @param expected {Array} expected output. + * @param aAccOrElmOrID identifier to get an accessible to test. + * @param aOldAccOrElmOrID optional identifier to get an accessible relative to + * the |aAccOrElmOrID|. + * @param aGenerator the output generator to use when generating accessible + * output + * + * Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be + * scoped to the "root" element in markup. + */ +function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) { + var accessible = getAccessible(aAccOrElmOrID); + var oldAccessible = aOldAccOrElmOrID !== null ? + getAccessible(aOldAccOrElmOrID || 'root') : null; + var context = new PivotContext(accessible, oldAccessible); + var output = aGenerator.genForContext(context); + + // Create a version of the output that has null members where we have + // null members in the expected output. Those are indexes that are not testable + // because of the changing nature of the test (different window names), or strings + // that are inaccessible to us, like the title of parent documents. + var masked_output = []; + for (var i=0; i < output.length; i++) { + if (expected[i] === null) { + masked_output.push(null); + } else { + masked_output[i] = typeof output[i] === "string" ? output[i].trim() : + output[i]; + } + } + + isDeeply(masked_output, expected, + "Context output is correct for " + aAccOrElmOrID + + " (output: " + JSON.stringify(output) + ") ==" + + " (expected: " + JSON.stringify(expected) + ")"); +} + +/** + * Test object output generated array that includes names. + * Note: test ignores outputs without the name. + * + * @param aAccOrElmOrID identifier to get an accessible to test. + * @param aGenerator the output generator to use when generating accessible + * output + */ +function testObjectOutput(aAccOrElmOrID, aGenerator) { + var accessible = getAccessible(aAccOrElmOrID); + if (!accessible.name || !accessible.name.trim()) { + return; + } + var context = new PivotContext(accessible); + var output = aGenerator.genForObject(accessible, context); + var outputOrder; + try { + outputOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER); + } catch (ex) { + // PREF_UTTERANCE_ORDER not set. + outputOrder = 0; + } + var expectedNameIndex = outputOrder === 0 ? output.length - 1 : 0; + var nameIndex = output.indexOf(accessible.name); + + if (nameIndex > -1) { + ok(output.indexOf(accessible.name) === expectedNameIndex, + "Object output is correct for " + aAccOrElmOrID); + } +} + +/** + * Test object and context output for an accessible. + * + * @param expected {Array} expected output. + * @param aAccOrElmOrID identifier to get an accessible to test. + * @param aOldAccOrElmOrID optional identifier to get an accessible relative to + * the |aAccOrElmOrID|. + * @param aOutputKind the type of output + */ +function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aOutputKind) { + var generator; + if (aOutputKind === 1) { + generator = UtteranceGenerator; + } else { + generator = BrailleGenerator; + } + testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, generator); + // Just need to test object output for individual + // accOrElmOrID. + if (aOldAccOrElmOrID) { + return; + } + testObjectOutput(aAccOrElmOrID, generator); +} + +function testHints(expected, aAccOrElmOrID, aOldAccOrElmOrID) { + var accessible = getAccessible(aAccOrElmOrID); + var oldAccessible = aOldAccOrElmOrID !== null ? + getAccessible(aOldAccOrElmOrID || 'root') : null; + var context = new PivotContext(accessible, oldAccessible); + var hints = context.interactionHints; + + isDeeply(hints, expected, + "Context hitns are correct for " + aAccOrElmOrID + + " (hints: " + JSON.stringify(hints) + ") ==" + + " (expected: " + JSON.stringify(expected) + ")"); +} diff --git a/accessible/tests/mochitest/jsat/test_alive.html b/accessible/tests/mochitest/jsat/test_alive.html new file mode 100644 index 000000000..cd4eef712 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_alive.html @@ -0,0 +1,81 @@ +<html> + +<head> + <title>AccessFu test for enabling</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="./jsatcommon.js"></script> + <script type="application/javascript"> + + function prefStart() { + AccessFuTest.once_log("AccessFu:Enabled", () => + ok(AccessFu._enabled, "AccessFu was enabled again.")); + AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest); + // Start AccessFu via pref. + SpecialPowers.pushPrefEnv({"set": [['accessibility.accessfu.activate', 1]]}); + } + + // Listen for 'EventManager.stop' and enable AccessFu again. + function settingsStart() { + isnot(AccessFu._enabled, true, "AccessFu was disabled."); + // XXX: Bug 978076 - test start with SettingsManager. + //navigator.mozSettings.createLock().set( + // {'accessibility.screenreader': false}); + AccessFuTest.once_log("EventManager.start", () => { + ok(AccessFu._enabled, "AccessFu was enabled again."); + AccessFuTest.nextTest(); + }); + AccessFu._enable(); + } + + // Make sure EventManager is started again. + function settingsStop() { + ok(AccessFu._enabled, "AccessFu was enabled again."); + // XXX: Bug 978076 - test stop with SettingsManager. + //navigator.mozSettings.createLock().set( + // {'accessibility.screenreader': false}); + AccessFuTest.once_log("EventManager.stop", () => { + isnot(AccessFu._enabled, "AccessFu was disabled."); + AccessFuTest.finish(); + }); + AccessFu._disable(); + } + + // Listen for initial 'EventManager.start' and disable AccessFu. + function prefStop() { + ok(AccessFu._enabled, "AccessFu was started via preference."); + AccessFuTest.once_log("AccessFu:Disabled", () => + isnot(AccessFu._enabled, true, "AccessFu was disabled.")); + AccessFuTest.once_log("EventManager.stop", AccessFuTest.nextTest); + + SpecialPowers.pushPrefEnv({"set": [['accessibility.accessfu.activate', 0]]}); + } + + function doTest() { + AccessFuTest.addFunc(prefStart); + AccessFuTest.addFunc(prefStop); + AccessFuTest.addFunc(settingsStart); + AccessFuTest.addFunc(settingsStop); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); // Will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> +<body> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307" + title="[AccessFu] Add mochitest for enabling"> + Mozilla Bug 811307 + </a> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_content_integration.html b/accessible/tests/mochitest/jsat/test_content_integration.html new file mode 100644 index 000000000..809f79726 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_content_integration.html @@ -0,0 +1,343 @@ +<!DOCTYPE html> +<html> +<head> + <title>Tests AccessFu content integration</title> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"> + </script> + <script type="application/javascript" + src="chrome://mochikit/content/chrome-harness.js"> + </script> + + <script type="application/javascript" src="../common.js"></script> + <script type="application/javascript" src="../browser.js"></script> + <script type="application/javascript" src="../events.js"></script> + <script type="application/javascript" src="../role.js"></script> + <script type="application/javascript" src="../states.js"></script> + <script type="application/javascript" src="../layout.js"></script> + <script type="application/javascript" src="jsatcommon.js"></script> + + <script type="application/javascript"> + function doTest() { + var doc = currentTabDocument(); + var iframe = doc.createElement('iframe'); + iframe.id = 'iframe'; + iframe.mozbrowser = true; + iframe.addEventListener('mozbrowserloadend', function () { + var contentTest = new AccessFuContentTest( + [ + // Simple traversal forward + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange( + ['Traversal Rule test document', 'Phone status bar'], + { focused: 'body' })], + [ContentMessages.simpleMovePrevious, new ExpectedNoMove()], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.simpleMoveNext, new ExpectedCursorChange( + ['such app', 'wow', {'string': 'headingLevel', 'args': [1]}], + { focused: 'iframe' })], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], + + // check checkbox + [ContentMessages.activateCurrent(), + new ExpectedClickAction({ no_android: true }), + new ExpectedCheckAction(true)], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['much range', {'string': 'label'}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])], + [ContentMessages.moveOrAdjustUp(), new ExpectedValueChange('6')], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Light', {"string": "stateOff"}, {'string': 'switch'}])], + // switch on + [ContentMessages.activateCurrent(), + new ExpectedClickAction({ no_android: true }), + new ExpectedSwitchAction(true)], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['slider', '0', {'string': 'slider'}])], + + // Simple traversal backward + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['Light', {"string": "stateOn"}, {'string': 'switch'}])], + // switch off + [ContentMessages.activateCurrent(), + new ExpectedClickAction({ no_android: true }), + new ExpectedSwitchAction(false)], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['such app', 'much range', '6', {'string': 'slider'}])], + [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange('5')], + [ContentMessages.androidScrollForward(), new ExpectedValueChange('6')], + [ContentMessages.androidScrollBackward(), new ExpectedValueChange('5')], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['much range', {'string': 'label'}])], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['many option', {'string': 'stateChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], + // uncheck checkbox + [ContentMessages.activateCurrent(), + new ExpectedClickAction({ no_android: true }), + new ExpectedCheckAction(false)], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['wow', {'string': 'headingLevel', 'args': [1]}])], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['Phone status bar'])], + + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + // Moving to the absolute last item from an embedded document + // fails. Bug 972035. + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange( + ['such app', 'wow', {'string': 'headingLevel', 'args': [1]}])], + // Move from an inner frame to the last element in the parent doc + [ContentMessages.simpleMoveLast, + new ExpectedCursorChange( + ['slider', '0', {'string': 'slider'}], { b2g_todo: true })], + + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedCursorChange(['Back', {"string": "pushbutton"}])], + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedCursorChange(['such app', 'many option', {'string': 'stateNotChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])], + // Calling AdjustOrMove should adjust the range. + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedValueChange('4')], + [ContentMessages.moveOrAdjustUp('FormElement'), + new ExpectedValueChange('5')], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['much range', {'string': 'label'}])], + [ContentMessages.moveOrAdjustUp('FormElement'), + new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], + [ContentMessages.moveOrAdjustUp('FormElement'), + new ExpectedCursorChange(['Back', {"string": "pushbutton"}])], + + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Moving to the absolute first item from an embedded document + // fails. Bug 972035. + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['such app', 'wow', {'string': 'headingLevel', 'args': [1]}])], + [ContentMessages.simpleMoveNext, new ExpectedCursorChange( + ['many option', {'string': 'stateNotChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], + [ContentMessages.simpleMoveFirst, + new ExpectedCursorChange(['Phone status bar'], { b2g_todo: true })], + + // Reset cursors + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Current virtual cursor's position's name changes + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.focusSelector('button#fruit', false), + new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])], + [doc.defaultView.renameFruit, new ExpectedNameChange('banana')], + + // Name and value changes inside a live-region (no cursor present) + [doc.defaultView.renameSlider, + new ExpectedNameChange('mover')], + [doc.defaultView.changeSliderValue, + new ExpectedValueChange('medium')], + + // Blur button and reset cursor + [ContentMessages.focusSelector('button#fruit', true), null], + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Move cursor with focus in outside document + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.focusSelector('button#home', false), + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], + + // Blur button and reset cursor + [ContentMessages.focusSelector('button#home', true), null], + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Set focus on element outside of embedded frame while + // cursor is in frame + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['such app', 'wow', {'string': 'headingLevel', 'args': [1]}])], + [ContentMessages.focusSelector('button#home', false), + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], + + // Blur button and reset cursor + [ContentMessages.focusSelector('button#home', true), null], + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // XXX: Set focus on iframe itself. + // XXX: Set focus on element in iframe when cursor is outside of it. + // XXX: Set focus on element in iframe when cursor is in iframe. + + // aria-hidden element that the virtual cursor is positioned on + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [doc.defaultView.ariaHideBack, + new ExpectedCursorChange( + ["such app", "wow", {"string": "headingLevel","args": [1]}])], + // Changing aria-hidden attribute twice and making sure that the event + // is fired only once when the actual change happens. + [doc.defaultView.ariaHideBack], + [doc.defaultView.ariaShowBack], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // aria-hidden on the iframe that has the vc. + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['such app', 'wow', {'string': 'headingLevel', 'args': [1]}])], + [doc.defaultView.ariaHideIframe, + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], + [doc.defaultView.ariaShowIframe], + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // aria-hidden element and auto Move + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [doc.defaultView.ariaHideBack], + [ContentMessages.focusSelector('button#back', false), + // Must not speak Back button as it is aria-hidden + new ExpectedCursorChange( + ["such app", "wow", {"string": "headingLevel","args": [1]}])], + [doc.defaultView.ariaShowBack], + [ContentMessages.focusSelector('button#back', true), null], + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Open dialog in outer doc, while cursor is also in outer doc + [ContentMessages.simpleMoveLast, + new ExpectedCursorChange(['Traversal Rule test document', 'mover', + 'medium', {'string': 'slider'}])], + [doc.defaultView.showAlert, + new ExpectedCursorChange(['This is an alert!', + {'string': 'headingLevel', 'args': [1]}, + {'string': 'dialog'}])], + + [doc.defaultView.hideAlert, + new ExpectedCursorChange(['Traversal Rule test document', 'mover', + 'medium', {'string': 'slider'}])], + + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Open dialog in outer doc, while cursor is in inner frame + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange( + ['such app', 'wow', {'string': 'headingLevel', 'args': [1]}])], + [doc.defaultView.showAlert, new ExpectedCursorChange(['This is an alert!', + {'string': 'headingLevel', 'args': [1]}, + {'string': 'dialog'}])], + + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Do you agree?'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Yes', {'string': 'pushbutton'}])], + [ContentMessages.activateCurrent(), + new ExpectedClickAction(), + new ExpectedCursorChange( + ['such app', 'wow', {'string': 'headingLevel', 'args': [1]}])], + + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + + // Open dialog, then focus on something when closing + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Traversal Rule test document', 'Phone status bar'])], + [doc.defaultView.showAlert, + new ExpectedCursorChange(['This is an alert!', + {'string': 'headingLevel', 'args': [1]}, {'string': 'dialog'}])], + + [function hideAlertAndFocusHomeButton() { + doc.defaultView.hideAlert(); + doc.querySelector('button#home').focus(); + }, new ExpectedCursorChange(['Traversal Rule test document', + 'Home', {'string': 'pushbutton'}])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['banana', {'string': 'pushbutton'}])] + [ContentMessages.simpleMoveNext, new ExpectedNoMove()] + ]); + + addA11yLoadEvent(function() { + contentTest.start(function () { + closeBrowserWindow(); + SimpleTest.finish(); + }); + }, doc.defaultView) + }); + iframe.src = 'data:text/html;charset=utf-8,' + doc.defaultView.frameContents; + doc.getElementById('appframe').appendChild(iframe); + } + + SimpleTest.waitForExplicitFinish(); + addLoadEvent( + function () { + openBrowserWindow( + function () { + SpecialPowers.pushPrefEnv({ + 'set': [ + // TODO: remove this as part of bug 820712 + ['network.disable.ipc.security', true], + + + ['dom.ipc.browser_frames.oop_by_default', true], + ['dom.mozBrowserFramesEnabled', true], + ['browser.pagethumbnails.capturing_disabled', true] + ] + }, doTest) }, + getRootDirectory(window.location.href) + 'doc_content_integration.html'); + }); + </script> +</head> +<body id="body"> + + <a target="_blank" + title="Add tests for OOP message handling and general integration" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=972047">Mozilla Bug 933808</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_content_text.html b/accessible/tests/mochitest/jsat/test_content_text.html new file mode 100644 index 000000000..558b819e9 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_content_text.html @@ -0,0 +1,292 @@ +<!DOCTYPE html> +<html> +<head> + <title>Tests AccessFu content integration</title> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"> + </script> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"> + </script> + <script type="application/javascript" + src="chrome://mochikit/content/chrome-harness.js"> + </script> + + <script type="application/javascript" src="../common.js"></script> + <script type="application/javascript" src="../browser.js"></script> + <script type="application/javascript" src="../events.js"></script> + <script type="application/javascript" src="../role.js"></script> + <script type="application/javascript" src="../states.js"></script> + <script type="application/javascript" src="../layout.js"></script> + <script type="application/javascript" src="jsatcommon.js"></script> + + <script type="application/javascript"> + function doTest() { + var doc = currentTabDocument(); + var textTest = new AccessFuContentTest( + [ + // Read-only text tests + [ContentMessages.simpleMoveFirst, + new ExpectedCursorChange( + ['Text content test document', 'These are my awards, Mother. ' + + 'From Army. The seal is for marksmanship, and the gorilla is ' + + 'for sand racing.'])], + [ContentMessages.moveNextBy('word'), + new ExpectedCursorTextChange('These', 0, 5)], + [ContentMessages.moveNextBy('word'), + new ExpectedCursorTextChange('are', 6, 9)], + [ContentMessages.moveNextBy('word'), + new ExpectedCursorTextChange('my', 10, 12)], + [ContentMessages.moveNextBy('word'), + new ExpectedCursorTextChange('awards,', 13, 20)], + [ContentMessages.moveNextBy('word'), + new ExpectedCursorTextChange('Mother.', 21, 28)], + [ContentMessages.movePreviousBy('word'), + new ExpectedCursorTextChange('awards,', 13, 20)], + [ContentMessages.movePreviousBy('word'), + new ExpectedCursorTextChange('my', 10, 12)], + [ContentMessages.movePreviousBy('word'), + new ExpectedCursorTextChange('are', 6, 9)], + [ContentMessages.movePreviousBy('word'), + new ExpectedCursorTextChange('These', 0, 5)], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['You\'re a good guy, mon frere. ' + + 'That means brother in French. ' + + 'I don\'t know how I know that. ' + + 'I took four years of Spanish.'])], + // XXX: Word boundary should be past the apostraphe. + [ContentMessages.moveNextBy('word'), + new ExpectedCursorTextChange('You\'re', 0, 6, + { android_todo: true /* Bug 980512 */})], + + // Editable text tests. + [ContentMessages.focusSelector('textarea'), + new ExpectedAnnouncement('editing'), + new ExpectedEditState({ + editing: true, + multiline: true, + atStart: true, + atEnd: false + }), + new ExpectedCursorChange( + ['Please refrain from Mayoneggs during this salmonella scare.', + {string: 'textarea'}]), + new ExpectedTextSelectionChanged(0, 0) + ], + [ContentMessages.activateCurrent(10), + new ExpectedTextCaretChanged(0, 10), + new ExpectedEditState({ editing: true, + multiline: true, + atStart: false, + atEnd: false }), + new ExpectedTextSelectionChanged(10, 10)], + [ContentMessages.activateCurrent(20), + new ExpectedTextCaretChanged(10, 20), + new ExpectedTextSelectionChanged(20, 20) + ], + [ContentMessages.moveCaretNextBy('word'), + new ExpectedTextCaretChanged(20, 29), + new ExpectedTextSelectionChanged(29, 29) + ], + [ContentMessages.moveCaretNextBy('word'), + new ExpectedTextCaretChanged(29, 36), + new ExpectedTextSelectionChanged(36, 36) + ], + [ContentMessages.moveCaretNextBy('character'), + new ExpectedTextCaretChanged(36, 37), + new ExpectedTextSelectionChanged(37, 37) + ], + [ContentMessages.moveCaretNextBy('character'), + new ExpectedTextCaretChanged(37, 38), + new ExpectedTextSelectionChanged(38, 38) + ], + [ContentMessages.moveCaretNextBy('paragraph'), + new ExpectedTextCaretChanged(38, 59), + new ExpectedTextSelectionChanged(59, 59) + ], + [ContentMessages.moveCaretPreviousBy('word'), + new ExpectedTextCaretChanged(53, 59), + new ExpectedTextSelectionChanged(53, 53) + ], + + // bug xxx + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange( + ['So we don\'t get dessert?', {string: 'label'}], + { focused: 'html'}), + new ExpectedAnnouncement('navigating'), + new ExpectedEditState({ + editing: false, + multiline: false, + atStart: true, + atEnd: false })], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange( + [{ string : 'entry' }], + { focused: 'html'})], + [ContentMessages.activateCurrent(0), + new ExpectedClickAction(), + new ExpectedAnnouncement('editing'), + new ExpectedEditState({ + editing: true, + multiline: false, + atStart: true, + atEnd: true + }, { focused: 'input[type=text]' }), + new ExpectedTextSelectionChanged(0, 0), + new ExpectedTextSelectionChanged(0, 0) + ], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange( + ['So we don\'t get dessert?', {string: 'label'}]), + new ExpectedAnnouncement('navigating'), + new ExpectedEditState({ + editing: false, + multiline: false, + atStart: true, + atEnd: false + },{ focused: 'html' }) + ], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange( + [{ string : 'entry' }], + { focused: 'html'})], + [ContentMessages.activateCurrent(0), + new ExpectedClickAction(), + new ExpectedAnnouncement('editing'), + new ExpectedEditState({ + editing: true, + multiline: false, + atStart: true, + atEnd: true + }, + { focused: 'input[type=text]' }), + new ExpectedTextSelectionChanged(0, 0)], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange( + [ 'So we don\'t get dessert?', {string: 'label'} ]), + new ExpectedAnnouncement('navigating'), + new ExpectedEditState({ + editing: false, + multiline: false, + atStart: true, + atEnd: false + }, { focused: 'html' })], + + [ContentMessages.focusSelector('input'), + new ExpectedAnnouncement('editing'), + new ExpectedEditState({ + editing: true, + multiline: false, + atStart: true, + atEnd: true + }), + new ExpectedCursorChange([{string: 'entry'}]), + new ExpectedTextSelectionChanged(0, 0) + ], + [function() { + SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 3]]}, typeKey('a')()); + }, + new ExpectedTextChanged('a'), + new ExpectedTextSelectionChanged(1, 1), + ], + [typeKey('b'), + new ExpectedTextChanged('b'), + new ExpectedTextSelectionChanged(2, 2), + ], + [typeKey('c'), + new ExpectedTextChanged('c'), + new ExpectedTextSelectionChanged(3, 3), + ], + [typeKey('d'), + new ExpectedTextChanged('d'), + new ExpectedTextSelectionChanged(4, 4), + ], + [typeKey(' '), + new ExpectedTextChanged(' abcd'), + new ExpectedTextSelectionChanged(5, 5), + ], + [typeKey('e'), + new ExpectedTextChanged('e'), + new ExpectedTextSelectionChanged(6, 6), + ], + [function() { + SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 2]]}, typeKey('a')()); + }, + new ExpectedTextChanged(''), + new ExpectedTextSelectionChanged(7, 7), + ], + [typeKey('d'), + new ExpectedTextChanged(''), + new ExpectedTextSelectionChanged(8, 8), + ], + [typeKey(' '), + new ExpectedTextChanged(' ead'), + new ExpectedTextSelectionChanged(9, 9), + ], + [function() { + SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 1]]}, typeKey('f')()); + }, + new ExpectedTextChanged('f'), + new ExpectedTextSelectionChanged(10, 10), + ], + [typeKey('g'), + new ExpectedTextChanged('g'), + new ExpectedTextSelectionChanged(11, 11), + ], + [typeKey(' '), + new ExpectedTextChanged(' '), + new ExpectedTextSelectionChanged(12, 12), + ], + [function() { + SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 0]]}, typeKey('f')()); + }, + new ExpectedTextChanged(''), + new ExpectedTextSelectionChanged(13, 13), + ], + [typeKey('g'), + new ExpectedTextChanged(''), + new ExpectedTextSelectionChanged(14, 14), + ], + [typeKey(' '), + new ExpectedTextChanged(''), + new ExpectedTextSelectionChanged(15, 15), + ], + ]); + + const KEYBOARD_ECHO_SETTING = 'accessibility.accessfu.keyboard_echo'; + function typeKey(key) { + return function() { synthesizeKey(key, {}, currentTabWindow()); }; + } + + addA11yLoadEvent(function() { + textTest.start(function () { + closeBrowserWindow(); + SimpleTest.finish(); + }); + }, doc.defaultView); + } + + SimpleTest.waitForExplicitFinish(); + addLoadEvent( + function () { + openBrowserWindow( + doTest, + getRootDirectory(window.location.href) + "doc_content_text.html"); + }); + </script> +</head> +<body id="body"> + + <a target="_blank" + title="Add tests for text editing and navigating" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=972047">Mozilla Bug 933808</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_explicit_names.html b/accessible/tests/mochitest/jsat/test_explicit_names.html new file mode 100644 index 000000000..fb7ed2022 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_explicit_names.html @@ -0,0 +1,191 @@ +<html> +<head> + <title>[AccessFu] Trust explicitly associated names when speaking certain elements</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="output.js"></script> + <script type="application/javascript"> + + function doTest() { + // Test the following accOrElmOrID. + var tests = [{ + accOrElmOrID: "anchor1", + expected: [{"string": "link"}, "title"] + }, { + accOrElmOrID: "anchor2", + expected: [{"string": "link"}, "This is a link"] + }, { + accOrElmOrID: "button1", + expected: [{"string": "pushbutton"}, "Press me"] + }, { + accOrElmOrID: "button2", + expected: [{"string": "pushbutton"}, "Press me"] + }, { + accOrElmOrID: "textarea1", + expected: [{"string": "textarea"}, "This is the text area text.", + "Test Text Area"] + }, { + accOrElmOrID: "textarea2", + expected: [{"string": "textarea"}, "This is the text area text."] + }, { + accOrElmOrID: "heading1", + expected: [{"string": "headingLevel", "args": [1]}, "Test heading", + "This is the heading."] + }, { + accOrElmOrID: "heading1", + oldAccOrElmOrID: null, + expected: [null /* parent doc title */, document.title, + {"string": "headingLevel", "args": [1]}, "Test heading", + "This is the heading."] + }, { + accOrElmOrID: "heading2", + expected: [{"string": "headingLevel", "args": [1]}, + "This is the heading."] + }, { + accOrElmOrID: "list", + expected: [{"string": "list"}, {"string": "listItemsCount", "count": 2}, + "Test List", {"string": "listStart"}, "Top of the list", + {"string": "listEnd"}, "2.", "list two"] + }, { + accOrElmOrID: "dlist", + expected: [{"string": "definitionlist"}, + {"string": "listItemsCount", "count": 0.5}, "Test Definition List", + "dd one"] + }, { + accOrElmOrID: "li_one", + expected: [{"string": "list"}, {"string": "listItemsCount", "count": 2}, + "Test List", {"string": "listStart"}, "Top of the list"] + }, { + accOrElmOrID: "li_two", + expected: [{"string": "list"}, {"string": "listItemsCount", "count": 2}, + "Test List", {"string": "listEnd"}, "2.", "list two"] + }, { + accOrElmOrID: "cell", + expected: [{"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 1}, "Fruits and vegetables", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "List of Fruits", + {"string": "list"}, {"string": "listItemsCount", "count": 4}, + {"string": "listStart"}, {"string": "link"}, "Apples", + {"string": "link"}, "Bananas", + {"string": "link"}, "Peaches", {"string": "listEnd"}, + {"string": "link"}, "Plums"] + }, { + accOrElmOrID: "app.net", + expected: [{"string": "list"}, {"string": "listItemsCount", "count": 2}, + {"string": "listStart"}, {"string": "link"}, "star", + {"string": "listEnd"}, {"string": "link"}, "repost"] + }, { + // Test pivot to list from li_one. + accOrElmOrID: "list", + oldAccOrElmOrID: "li_one", + expected: [{"string": "list"}, {"string": "listItemsCount", "count": 2}, + "Test List", {"string": "listStart"}, "Top of the list", + {"string": "listEnd"}, "2.", "list two"] + }, { + // Test pivot to li_one from list. + accOrElmOrID: "li_one", + oldAccOrElmOrID: "list", + expected: [{"string": "listStart"}, "Top of the list"] + }, { + // Test pivot to "apples" link from the table cell. + accOrElmOrID: "apples", + oldAccOrElmOrID: "cell", + expected: [{"string": "list"}, {"string": "listItemsCount", "count": 4}, + {"string": "listStart"}, {"string": "link"}, "Apples"] + }, { + // Test pivot to the table cell from the "apples" link. + accOrElmOrID: "cell", + oldAccOrElmOrID: "apples", + expected: ["List of Fruits", {"string": "list"}, + {"string": "listItemsCount", "count": 4}, {"string": "listStart"}, + {"string": "link"}, "Apples", {"string": "link"}, "Bananas", + {"string": "link"}, "Peaches", {"string": "listEnd"}, + {"string": "link"}, "Plums"] + }]; + + SpecialPowers.pushPrefEnv({"set": [[PREF_UTTERANCE_ORDER, 0]]}, function() { + // Test various explicit names vs the utterance generated from subtrees. + tests.forEach(function run(test) { + testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1); + }); + SimpleTest.finish(); + }); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + <div id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=845870" + title="[AccessFu] Trust explicitly associated names when speaking certain elements"> + Mozilla Bug 845870 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + <button id="button1" aria-label="Press me">This is not a name</button> + <button id="button2"> + Press me + </button> + <a id="anchor1" href="#test" title="title"></a> + <a id="anchor2" href="#test">This is a link</a> + <textarea id="textarea1" title="Test Text Area" cols="80" rows="5">This is the text area text.</textarea> + <textarea id="textarea2" cols="80" rows="5"> + This is the text area text. + </textarea> + <h1 id="heading1" title="Test heading">This is the heading.</h1> + <h1 id="heading2"> + This is the heading. + </h1> + <ol id="list" title="Test List"> + <li id="li_one" aria-label="Top of the list">list one</li> + <li id="li_two">list two</li> + </ol> + <dl id="dlist" title="Test Definition List"> + <dd id="dd_one">dd one</dd> + </dl> + <table> + <caption>Fruits and vegetables</caption> + <tr> + <td id="cell" aria-label="List of Fruits"> + <ul style="list-style-type: none;"> + <li><a id="apples" href="#">Apples</a></li> + <li><a id="bananas" href="#">Bananas</a></li> + <li><a href="#">Peaches</a></li> + <li> + <a href="#"> + + Plums + </a> + </li> + </ul> + </td> + </tr> + </table> + <!-- app.net --> + <ul id="app.net" class="unstyled ul-horizontal yui3-u fixed-right ta-right" style="list-style-type: none;"> + <li class="yui3-u"> + <a href="#star" data-starred="0" data-star-button="1" data-post-id="5098826" aria-label="star"> + Garbage + </a> + </li> + <li class="yui3-u repost"> + <a href="#repost" title="repost" data-repost-button="1" data-reposted="0" data-post-id="5098826"> + <i aria-label="repost" class="icon-repost"></i> + </a> + </li> + </ul> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_gesture_tracker.html b/accessible/tests/mochitest/jsat/test_gesture_tracker.html new file mode 100644 index 000000000..af2755455 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_gesture_tracker.html @@ -0,0 +1,51 @@ +<html> + +<head> + <title>AccessFu tests for gesture tracker.</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../common.js"></script> + <script type="application/javascript" src="../layout.js"></script> + <script type="application/javascript" src="./jsatcommon.js"></script> + <script type="application/javascript" src="./dom_helper.js"></script> + <script type="application/javascript"> + + function startGestureTracker() { + GestureTracker.reset(); + AccessFuTest.nextTest(); + } + + function stopGestureTracker() { + GestureTracker.reset(); + AccessFuTest.finish(); + } + + function doTest() { + loadJSON("./gestures.json", function onSuccess(gestures) { + AccessFuTest.addFunc(startGestureTracker); + AccessFuTest.sequenceCleanup = GestureTracker.reset.bind( + GestureTracker); + gestures.forEach(AccessFuTest.addSequence); + AccessFuTest.addFunc(stopGestureTracker); + AccessFuTest.waitForExplicitFinish(); + Logger.logLevel = Logger.GESTURE; + AccessFuTest.runTests(); + }); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> +<body> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=981015" + title="AccessFu tests for gesture tracker."> + Mozilla Bug 981015 + </a> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_hints.html b/accessible/tests/mochitest/jsat/test_hints.html new file mode 100644 index 000000000..d5691b97a --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_hints.html @@ -0,0 +1,89 @@ +<html> +<head> + <title> [AccessFu] Interaction Hints </title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="output.js"></script> + <script type="application/javascript"> + + function doTest() { + var tests = [{ + accOrElmOrID: 'can_wheel', + expectedHints: ['Swipe with two fingers to move between pages'] + }, { + accOrElmOrID: 'nested_link', + expectedHints: [{string: 'link-hint'}, + 'Swipe with two fingers to move between pages'] + }, { + accOrElmOrID: 'nested_link', + oldAccOrElmOrID: 'can_wheel', + expectedHints: [{string: 'link-hint'}] + }, { + accOrElmOrID: 'link_with_default_hint', + expectedHints: [{string: 'link-hint'}] + }, { + accOrElmOrID: 'link_with_hint_override', + expectedHints: ['Tap and hold to get to menu'] + }, { + accOrElmOrID: 'button_with_default_hint', + expectedHints: [{string: 'pushbutton-hint'}] + }, { + accOrElmOrID: 'button_with_hint_override', + expectedHints: ['Tap and hold to activate'] + }, { + accOrElmOrID: 'nested_link2', + expectedHints: [{string: 'link-hint'}] + }, { + accOrElmOrID: 'nested_link3', + expectedHints: [{string: 'link-hint'}, {string: 'pushbutton-hint'}, + "Double tap and hold to activate"] + }, { + accOrElmOrID: 'menuitemradio', + expectedHints: [{string: 'radiomenuitem-hint'}] + }]; + + // Test hints. + tests.forEach(function run(test) { + testHints(test.expectedHints, test.accOrElmOrID, test.oldAccOrElmOrID); + }); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + <div id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069574" + title="[AccessFu] Interaction Hints"> + Mozilla Bug 1069574 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + <span role="region" id="can_wheel" aria-moz-hint="Swipe with two fingers to move between pages"> + <a href="#" id="nested_link">I can be clicked</a> + </span> + <span role="region" aria-moz-hint=""> + <a><a href="#" id="nested_link2">I can be clicked</a></a> + </span> + <span role="region" aria-moz-hint="Double tap and hold to activate"> + <button><a href="#" id="nested_link3">I can be clicked</a></button> + </span> + <a href="#" id="link_with_default_hint">I can be clicked</a> + <a href="#" id="link_with_hint_override" aria-moz-hint="Tap and hold to get to menu">I am a special link</a> + <button id="button_with_default_hint">Toggle</button> + <button id="button_with_hint_override" aria-moz-hint="Tap and hold to activate">Special</button> + <span id="menuitemradio" role="menuitemradio">Item 1</span> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_landmarks.html b/accessible/tests/mochitest/jsat/test_landmarks.html new file mode 100644 index 000000000..8b1a16f83 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_landmarks.html @@ -0,0 +1,183 @@ +<html> +<head> + <title> [AccessFu] Speak landmarks</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="output.js"></script> + <script type="application/javascript" + src="jsatcommon.js"></script> + <script type="application/javascript"> + + function doTest() { + // Test the following accOrElmOrID. + var tests = [{ + accOrElmOrID: "nav", + expectedUtterance: [[{"string": "navigation"}, "a nav"], + ["a nav", {"string": "navigation"}]], + expectedBraille: [[{"string": "navigation"}, "a nav"], + ["a nav", {"string": "navigation"}]] + }, { + accOrElmOrID: "main", + expectedUtterance: [[{"string": "main"}, "a main area"], + ["a main area", {"string": "main"}]], + expectedBraille: [[{"string": "main"}, "a main area"], + ["a main area", {"string": "main"}]] + }, { + accOrElmOrID: "header", + expectedUtterance: [ + [{"string": "banner"}, {"string": "header"}, "a header"], + ["a header", {"string": "header"}, {"string": "banner"}]], + expectedBraille: [ + [{"string": "banner"}, {"string": "headerAbbr"}, "a header"], + ["a header", {"string": "headerAbbr"}, {"string": "banner"}]] + }, { + accOrElmOrID: "footer", + expectedUtterance: [ + [{"string": "contentinfo"}, {"string": "footer"}, "a footer"], + ["a footer", {"string": "footer"}, {"string": "contentinfo"}]], + expectedBraille: [ + [{"string": "contentinfo"}, {"string": "footerAbbr"}, "a footer"], + ["a footer", {"string": "footerAbbr"}, {"string": "contentinfo"}]] + }, { + accOrElmOrID: "article_header", + expectedUtterance: [ + [{"string": "header"}, "a header within an article"], + ["a header within an article", {"string": "header"}]], + expectedBraille: [ + [{"string": "headerAbbr"}, "a header within an article"], + ["a header within an article", {"string": "headerAbbr"}]], + }, { + accOrElmOrID: "article_footer", + expectedUtterance: [ + [{"string": "footer"}, "a footer within an article"], + ["a footer within an article", {"string": "footer"}]], + expectedBraille: [ + [{"string": "footerAbbr"}, "a footer within an article"], + ["a footer within an article", {"string": "footerAbbr"}]] + }, { + accOrElmOrID: "section_header", + expectedUtterance: [[{"string":"header"}, "a header within a section"], + ["a header within a section", {"string":"header"}]], + expectedBraille: [ + [{"string":"headerAbbr"}, "a header within a section"], + ["a header within a section", {"string":"headerAbbr"}]] + }, { + accOrElmOrID: "section_footer", + expectedUtterance: [ + [{"string": "footer"}, "a footer within a section"], + ["a footer within a section", {"string": "footer"}]], + expectedBraille: [ + [{"string": "footerAbbr"}, "a footer within a section"], + ["a footer within a section", {"string": "footerAbbr"}]] + }, { + accOrElmOrID: "aside", + expectedUtterance: [ + [{"string": "complementary"}, "by the way I am an aside"], + ["by the way I am an aside", {"string": "complementary"}]], + expectedBraille: [ + [{"string": "complementary"}, "by the way I am an aside"], + ["by the way I am an aside", {"string": "complementary"}]] + }, { + accOrElmOrID: "main_element", + expectedUtterance: [[{"string": "main"}, "another main area"], + ["another main area", {"string": "main"}]], + expectedBraille: [[{"string": "main"}, "another main area"], + ["another main area", {"string": "main"}]] + }, { + accOrElmOrID: "complementary", + expectedUtterance: [[{"string": "list"}, + {"string": "listItemsCount", "count": 1}, {"string": "complementary"}, + {"string": "listStart"}, "A complementary"], ["A complementary", + {"string": "listStart"}, {"string": "complementary"}, + {"string": "list"}, {"string": "listItemsCount", "count": 1}]], + expectedBraille: [["*", {"string": "complementary"}, "A complementary"], + ["*", "A complementary", {"string": "complementary"}]] + }, { + accOrElmOrID: "parent_main", + expectedUtterance: [[{"string": "main"}, "a parent main", + {"string": "complementary"}, "a child complementary"], + ["a parent main", "a child complementary", + {"string": "complementary"}, {"string": "main"}]], + expectedBraille: [[{"string": "main"}, "a parent main", + {"string": "complementary"}, "a child complementary"], + ["a parent main", "a child complementary", + {"string": "complementary"}, {"string": "main"}]] + }, { + accOrElmOrID: "child_complementary", + expectedUtterance: [[{"string": "main"}, {"string": "complementary"}, + "a child complementary"], ["a child complementary", + {"string": "complementary"}, {"string": "main"}]], + expectedBraille: [[{"string": "complementary"}, + "a child complementary"], ["a child complementary", + {"string": "complementary"}]] + }]; + + // Test outputs (utterance and braille) for landmarks. + function testOutputOrder(aOutputOrder) { + return function() { + SpecialPowers.pushPrefEnv({ + "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]] + }, function() { + tests.forEach(function run(test) { + testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 1); + testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 0); + }); + AccessFuTest.nextTest(); + }); + }; + } + + AccessFuTest.addFunc(testOutputOrder(0)); + AccessFuTest.addFunc(testOutputOrder(1)); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + <div id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=888256" + title="[AccessFu] Speak landmarks"> + Mozilla Bug 888256 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + <nav id="nav">a nav</nav> + <header id="header">a header</header> + <footer id="footer">a footer</footer> + <article id="article_with_header_and_footer"> + <header id="article_header">a header within an article</header> + <footer id="article_footer">a footer within an article</footer> + </article> + <section id="section_with_header_and_footer"> + <header id="section_header">a header within a section</header> + <footer id="section_footer">a footer within a section</footer> + </section> + <aside id="aside">by the way I am an aside</aside> + <article id="main" role="main">a main area</article> + <main id="main_element">another main area</main> + <ul style="list-style-type: none;"> + <li role="complementary" id="complementary"> + A complementary + </li> + </ul> + <main id="parent_main"> + a parent main + <p id="child_complementary" role="complementary">a child complementary</article> + </main> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_live_regions.html b/accessible/tests/mochitest/jsat/test_live_regions.html new file mode 100644 index 000000000..53828f1b1 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_live_regions.html @@ -0,0 +1,472 @@ +<html> + +<head> + <title>AccessFu tests for live regions support</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="./jsatcommon.js"></script> + <script type="application/javascript"> + + function startAccessFu() { + SpecialPowers.pushPrefEnv({"set": [['accessibility.accessfu.activate', 1]]}); + AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest); + } + + function stopAccessFu() { + SpecialPowers.pushPrefEnv({"set": [['accessibility.accessfu.activate', 0]]}); + AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish()); + } + + function hide(id) { + var element = document.getElementById(id); + element.style.display = "none"; + } + + function show(id) { + var element = document.getElementById(id); + element.style.display = "block"; + } + + function ariaHide(id) { + var element = document.getElementById(id); + element.setAttribute('aria-hidden', true); + } + + function ariaShow(id) { + var element = document.getElementById(id); + element.setAttribute('aria-hidden', false); + } + + function udpate(id, text, property) { + var element = document.getElementById(id); + element[property] = text; + } + + function updateText(id, text) { + udpate(id, text, "textContent"); + } + + function updateHTML(id, text) { + udpate(id, text, "innerHTML"); + } + + var tests = [{ + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "I will be hidden"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_hide1", "to_hide2", "to_hide3", "to_hide4"].forEach(id => hide(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "I will be hidden"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_hide_descendant1", "to_hide_descendant2", + "to_hide_descendant3", "to_hide_descendant4"].forEach(id => hide(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I will be shown"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_show1", "to_show2", "to_show3", "to_show4"].forEach(id => show(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I will be shown"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_show_descendant1", "to_show_descendant2", + "to_show_descendant3", "to_show_descendant4"].forEach(id => show(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "I will be hidden"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_hide5", "to_hide6", "to_hide7", "to_hide8", "to_hide9"].forEach(id => ariaHide(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "I will be hidden"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_hide_descendant5", "to_hide_descendant6", + "to_hide_descendant7", "to_hide_descendant8"].forEach(id => ariaHide(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I will be shown"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_show5", "to_show6", "to_show7", "to_show8", "to_show9"].forEach(id => ariaShow(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I will be shown"], + "options": { + "enqueue": true + } + }, + action: function action() { + ["to_show_descendant5", "to_show_descendant6", + "to_show_descendant7", "to_show_descendant8"].forEach(id => ariaShow(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "I will be hidden"], + "options": { + "enqueue": false + } + }, + action: function action() { + hide("to_hide_live_assertive"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "I will be hidden"], + "options": { + "enqueue": false + } + }, + action: function action() { + ariaHide("to_hide_live_assertive2"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I will be shown"], + "options": { + "enqueue": false + } + }, + action: function action() { + ["to_show_live_off", "to_show_live_assertive"].forEach(id => show(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I will be shown"], + "options": { + "enqueue": false + } + }, + action: function action() { + ["to_show_live_off2", "to_show_live_assertive2"].forEach(id => ariaShow(id)); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["Text Added"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateText("text_add", "Text Added"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["Text Added"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateHTML("text_add", "Text Added"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "Text Removed"], + "options": { + "enqueue": true + } + }, + action: function action() { + updateText("text_remove", ""); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["Descendant Text Added"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateText("text_add_descendant", "Descendant Text Added"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["Descendant Text Added"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateHTML("text_add_descendant", "Descendant Text Added"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "Descendant Text Removed"], + "options": { + "enqueue": true + } + }, + action: function action() { + updateText("text_remove_descendant", ""); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["Descendant Text Added"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateText("text_add_descendant2", "Descendant Text Added"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["Descendant Text Added"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateHTML("text_add_descendant2", "Descendant Text Added"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": [{"string": "hidden"}, "Descendant Text Removed"], + "options": { + "enqueue": true + } + }, + action: function action() { + updateText("text_remove_descendant2", ""); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I am replaced", {"string": "main"}], + "options": { + "enqueue": true + } + }, + action: function action() { + var region = document.getElementById("to_replace_region"); + var child = document.getElementById("to_replace"); + child.setAttribute("role", "main"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I am a replaced text"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateText("to_replace_text", "I am a replaced text"); + } + }, { + expected: { + "eventType": "liveregion-change", + "data": ["I am a replaced text"], + "options": { + "enqueue": false + } + }, + action: function action() { + updateHTML("to_replace_text", "I am a replaced text"); + } + }]; + + function doTest() { + AccessFuTest.addFunc(startAccessFu); + tests.forEach(function addTest(test) { + AccessFuTest.addFunc(function () { + AccessFuTest.once(test.expected, AccessFuTest.nextTest); + test.action(); + }); + }); + AccessFuTest.addFunc(stopAccessFu); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> +<body> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=795957" + title="[AccessFu] Support live regions"> + Mozilla Bug 795957 + </a> + <div id="root"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + + <p id="to_hide1">I should not be announced 1</p> + <p id="to_hide2" aria-live="polite">I should not be announced 2</p> + <p id="to_hide3" aria-live="assertive" aria-relevant="text">I should not be announced 3</p> + <p id="to_hide4" aria-live="polite" aria-relevant="all">I will be hidden</p> + + <p id="to_hide5" aria-hidden="true">I should not be announced 5</p> + <p id="to_hide6">I should not be announced 6</p> + <p id="to_hide7" aria-live="polite">I should not be announced 7</p> + <p id="to_hide8" aria-live="assertive" aria-relevant="text">I should not be announced 8</p> + <p id="to_hide9" aria-live="polite" aria-relevant="all">I will be hidden</p> + + <div> + <p id="to_hide_descendant1">I should not be announced 1</p> + </div> + <div aria-live="polite"> + <p id="to_hide_descendant2">I should not be announced 2</p> + </div> + <div aria-live="assertive" aria-relevant="text"> + <p id="to_hide_descendant3">I should not be announced 3</p> + </div> + <div aria-live="polite" aria-relevant="all"> + <p id="to_hide_descendant4">I will be hidden</p> + </div> + + <div> + <p id="to_hide_descendant5">I should not be announced 4</p> + </div> + <div aria-live="polite"> + <p id="to_hide_descendant6">I should not be announced 5</p> + </div> + <div aria-live="assertive" aria-relevant="text"> + <p id="to_hide_descendant7">I should not be announced 6</p> + </div> + <div aria-live="polite" aria-relevant="all"> + <p id="to_hide_descendant8">I will be hidden</p> + </div> + + <p id="to_show1" style="display: none">I should not be announced 1</p> + <p id="to_show2" aria-live="assertive" aria-relevant="text" style="display: none">I should not be announced 2</p> + <p id="to_show3" aria-live="polite" aria-relevant="removals" style="display: none">I should not be announced 3</p> + <p id="to_show4" aria-live="polite" aria-relevant="all" style="display: none">I will be shown</p> + + <p id="to_show5" aria-hidden="false">I should not be announced 5</p> + <p id="to_show6" aria-hidden="true">I should not be announced 6</p> + <p id="to_show7" aria-hidden="true" aria-live="assertive" aria-relevant="text">I should not be announced 7</p> + <p id="to_show8" aria-hidden="true" aria-live="polite" aria-relevant="removals">I should not be announced 8</p> + <p id="to_show9" aria-hidden="true" aria-live="polite" aria-relevant="all">I will be shown</p> + + <div> + <p id="to_show_descendant1" style="display: none">I should not be announced 1</p> + </div> + <div aria-live="polite" aria-relevant="removals"> + <p id="to_show_descendant2" style="display: none">I should not be announced 2</p> + </div> + <div aria-live="assertive" aria-relevant="text"> + <p id="to_show_descendant3" style="display: none">I should not be announced 3</p> + </div> + <div aria-live="polite" aria-relevant="all"> + <p id="to_show_descendant4" style="display: none">I will be shown</p> + </div> + + <div> + <p id="to_show_descendant5" aria-hidden="true">I should not be announced 5</p> + </div> + <div aria-live="polite" aria-relevant="removals"> + <p id="to_show_descendant6" aria-hidden="true">I should not be announced 6</p> + </div> + <div aria-live="assertive" aria-relevant="text"> + <p id="to_show_descendant7" aria-hidden="true">I should not be announced 7</p> + </div> + <div aria-live="polite" aria-relevant="all"> + <p id="to_show_descendant8" aria-hidden="true">I will be shown</p> + </div> + + <div aria-live="assertive" aria-relevant="all"> + <p id="to_hide_live_assertive">I will be hidden</p> + </div> + + <div aria-live="assertive" aria-relevant="all"> + <p id="to_hide_live_assertive2">I will be hidden</p> + </div> + <p id="to_show_live_assertive" aria-live="assertive" style="display: none">I will be shown</p> + + <p id="to_show_live_off" aria-live="off" style="display: none">I will not be shown</p> + + <p id="to_show_live_assertive2" aria-live="assertive" aria-hidden="true">I will be shown</p> + + <p id="to_show_live_off2" aria-live="off" aria-hidden="true">I will not be shown</p> + + <div id="to_replace_region" aria-live="polite" aria-relevant="all"> + <p id="to_replace">I am replaced</p> + </div> + + <p id="to_replace_text" aria-live="assertive" aria-relevant="text">I am going to be replaced</p> + + <p id="text_add" aria-live="assertive" aria-relevant="text"></p> + <p id="text_remove" aria-live="polite" aria-relevant="all">Text Removed</p> + + <div aria-live="assertive" aria-relevant="all"> + <p id="text_add_descendant"></p> + </div> + <div aria-live="polite" aria-relevant="text"> + <p id="text_remove_descendant">Descendant Text Removed</p> + </div> + <div aria-live="assertive" aria-relevant="text"> + <p id="text_add_descendant2"></p> + </div> + <div aria-live="polite" aria-relevant="all"> + <p id="text_remove_descendant2">Descendant Text Removed</p> + </div> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_output.html b/accessible/tests/mochitest/jsat/test_output.html new file mode 100644 index 000000000..ec2b289be --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_output.html @@ -0,0 +1,673 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=753984 +--> + <head> + <title>[AccessFu] utterance order test</title> + <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="./output.js"></script> + <script type="application/javascript" + src="./jsatcommon.js"></script> + <script type="application/javascript"> + + function doTest() { + // Test the following accOrElmOrID (with optional old accOrElmOrID). + // Note: each accOrElmOrID entry maps to a unique object utterance + // generator function within the UtteranceGenerator. + var tests = [{ + accOrElmOrID: "anchor", + expectedUtterance: [[{"string": "link"}, "title"], + ["title", {"string": "link"}]], + expectedBraille: [[{"string": "linkAbbr"}, "title"], + ["title", {"string": "linkAbbr"}]] + }, { + accOrElmOrID: "anchor_titleandtext", + expectedUtterance: [[{"string": "link"}, "goes to the tests -", + "Tests"], ["Tests", "- goes to the tests", {"string": "link"}]], + expectedBraille: [[{"string": "linkAbbr"}, "goes to the tests -", + "Tests"], ["Tests", "- goes to the tests", {"string": "linkAbbr"}]], + }, { + accOrElmOrID: "anchor_duplicatedtitleandtext", + expectedUtterance: [[{"string": "link"}, "Tests"], + ["Tests", {"string": "link"}]], + expectedBraille: [[{"string": "linkAbbr"}, "Tests"], + ["Tests", {"string": "linkAbbr"}]] + }, { + accOrElmOrID: "anchor_arialabelandtext", + expectedUtterance: [[{"string": "link"}, "goes to the tests - Tests"], + ["Tests - goes to the tests", {"string": "link"}]], + expectedBraille: [[{"string": "linkAbbr"}, + "goes to the tests - Tests"], ["Tests - goes to the tests", + {"string": "linkAbbr"}]], + }, { + accOrElmOrID: "textarea", + expectedUtterance: [[{"string": "textarea"}, + "This is the text area text."], ["This is the text area text.", + {"string": "textarea"}]], + expectedBraille: [[{"string": "textareaAbbr"}, + "This is the text area text."], ["This is the text area text.", + {"string": "textareaAbbr"}]], + }, { + accOrElmOrID: "heading", + expectedUtterance: [[{"string": "headingLevel", "args": [1]}, + "Test heading"], ["Test heading", + {"string": "headingLevel", "args": [1]}]], + expectedBraille: [[{"string": "headingAbbr"}, "Test heading"], + ["Test heading", {"string": "headingAbbr"}]] + }, { + accOrElmOrID: "list", + expectedUtterance: [[{"string": "list"}, + {"string": "listItemsCount", "count":1}, {"string": "listStart"}, + "1.", "list one"], ["1.", "list one", {"string": "listStart"}, + {"string": "list"}, {"string": "listItemsCount", "count":1}] + ], + expectedBraille: [[{"string": "listAbbr"}, "list one"], + ["list one", {"string": "listAbbr"}]] + }, { + accOrElmOrID: "dlist", + expectedUtterance: [[{"string": "definitionlist"}, + {"string": "listItemsCount", "count": 0.5}, "dd one"], ["dd one", + {"string": "definitionlist"}, + {"string": "listItemsCount", "count": 0.5}] + ], + expectedBraille: [[{"string": "definitionlistAbbr"}, "dd one"], + ["dd one", {"string": "definitionlistAbbr"}]] + }, { + accOrElmOrID: "li_one", + expectedUtterance: [[{"string": "list"}, + {"string": "listItemsCount", "count": 1}, {"string": "listStart"}, + "1.", "list one"], ["1.", "list one", {"string": "listStart"}, + {"string": "list"}, {"string": "listItemsCount", "count": 1}] + ], + expectedBraille: [["1.", "list one"], ["1.", "list one"]] + }, + { + accOrElmOrID: "li_two", + expectedUtterance: [[{"string": "list"}, + {"string": "listItemsCount", "count": 1}, {"string": "listStart"}, + "list two"], ["list two", {"string": "listStart"}, + {"string": "list"}, {"string": "listItemsCount", "count": 1}] + ], + expectedBraille: [["*", "list two"], ["*", "list two"]] + }, { + accOrElmOrID: "cell", + expectedUtterance: [[{"string":"table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 1}, "Fruits and vegetables", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, {"string": "list"}, + {"string": "listItemsCount", "count": 4}, {"string": "listStart"}, + {"string": "link"}, "Apples", {"string": "link"}, "Bananas", + {"string": "link"}, "Peaches", {"string": "listEnd"}, + {"string": "link"}, "Plums"], ["Apples", {"string": "link"}, + {"string": "listStart"}, "Bananas", {"string": "link"}, "Peaches", + {"string": "link"}, "Plums", {"string": "link"}, + {"string": "listEnd"}, {"string": "list"}, + {"string": "listItemsCount", "count": 4}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "Fruits and vegetables", + {"string":"table"}, {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 1}]], + expectedBraille: [[{"string": "cellInfoAbbr", "args": [ 1, 1]}, + {"string": "listAbbr"}, {"string": "linkAbbr"}, "Apples", + {"string": "linkAbbr"}, "Bananas", {"string": "linkAbbr"}, + "Peaches", {"string": "linkAbbr"}, "Plums"], ["Apples", + {"string": "linkAbbr"}, "Bananas", {"string": "linkAbbr"}, + "Peaches", {"string": "linkAbbr"}, "Plums", {"string": "linkAbbr"}, + {"string": "listAbbr"}, + {"string": "cellInfoAbbr", "args": [ 1, 1]}]] + }, { + accOrElmOrID: "date", + expectedUtterance: [[{"string": "textInputType_date"}, + {"string": "entry"}, "2011-09-29"], ["2011-09-29", + {"string": "textInputType_date"}, {"string": "entry"}]], + expectedBraille: [[{"string": "textInputType_date"}, + {"string": "entryAbbr"}, "2011-09-29"], ["2011-09-29", + {"string": "textInputType_date"}, {"string": "entryAbbr"}]] + }, { + accOrElmOrID: "email", + expectedUtterance: [[{"string": "textInputType_email"}, + {"string": "entry"}, "test@example.com"], ["test@example.com", + {"string": "textInputType_email"}, {"string": "entry"}]], + expectedBraille: [[{"string": "textInputType_email"}, + {"string": "entryAbbr"}, "test@example.com"], ["test@example.com", + {"string": "textInputType_email"}, {"string": "entryAbbr"}]] + }, { + accOrElmOrID: "search", + expectedUtterance: [[{"string": "textInputType_search"}, + {"string": "entry"}, "This is a search"], ["This is a search", + {"string": "textInputType_search"}, {"string": "entry"}]], + expectedBraille: [[{"string": "textInputType_search"}, + {"string": "entryAbbr"}, "This is a search"], ["This is a search", + {"string": "textInputType_search"}, {"string": "entryAbbr"}]] + }, { + accOrElmOrID: "tel", + expectedUtterance: [[{"string": "textInputType_tel"}, + {"string": "entry"}, "555-5555"], ["555-5555", + {"string": "textInputType_tel"}, {"string": "entry"}]], + expectedBraille: [[{"string": "textInputType_tel"}, + {"string": "entryAbbr"}, "555-5555"], ["555-5555", + {"string": "textInputType_tel"}, {"string": "entryAbbr"}]] + }, { + accOrElmOrID: "url", + expectedUtterance: [[{"string": "textInputType_url"}, + {"string": "entry"}, "http://example.com"], ["http://example.com", + {"string": "textInputType_url"}, {"string": "entry"}]], + expectedBraille: [[{"string": "textInputType_url"}, + {"string": "entryAbbr"}, "http://example.com"], + ["http://example.com", {"string": "textInputType_url"}, + {"string": "entryAbbr"}]] + }, { + accOrElmOrID: "textInput", + expectedUtterance: [[{"string": "entry"}, "This is text."], + ["This is text.", {"string": "entry"}]], + expectedBraille: [[{"string": "entryAbbr"}, "This is text."], + ["This is text.", {"string": "entryAbbr"}]] + }, { + // Test pivot to list from li_one. + accOrElmOrID: "list", + oldAccOrElmOrID: "li_one", + expectedUtterance: [[{"string": "list"}, + {"string": "listItemsCount", "count": 1}, {"string": "listStart"}, + "1.", "list one"], ["1.", "list one", {"string": "listStart"}, + {"string": "list"}, {"string": "listItemsCount", "count": 1}] + ], + expectedBraille: [[{"string": "listAbbr"}, "list one"], + ["list one", {"string": "listAbbr"}]] + }, { + // Test pivot to "apples" link from the table cell. + accOrElmOrID: "apples", + oldAccOrElmOrID: "cell", + expectedUtterance: [[{"string": "list"}, + {"string": "listItemsCount", "count": 4}, {"string": "listStart"}, + {"string": "link"}, "Apples"], ["Apples", {"string": "link"}, + {"string": "listStart"}, {"string": "list"}, + {"string": "listItemsCount", "count": 4}] + ], + expectedBraille: [["*", {"string": "linkAbbr"}, "Apples"], + ["*", "Apples", {"string": "linkAbbr"}]] + }, { + // Test pivot to "bananas" link from "apples" link. + accOrElmOrID: "bananas", + oldAccOrElmOrID: "apples", + expectedUtterance: [[{"string": "link"}, "Bananas"], + ["Bananas", {"string": "link"}]], + expectedBraille: [["*", {"string": "linkAbbr"}, "Bananas"], + ["*", "Bananas", {"string": "linkAbbr"}]] + }, { + // test unavailable state utterance + accOrElmOrID: "unavailableButton", + expectedUtterance: [[{"string": "stateUnavailable"}, + {"string": "pushbutton"}, "I am unavailable"], ["I am unavailable", + {"string": "stateUnavailable"}, {"string": "pushbutton"}]], + expectedBraille: [[{"string": "pushbuttonAbbr"}, "I am unavailable"], + ["I am unavailable", {"string": "pushbuttonAbbr"}]] + }, { + // test expanded state utterance + accOrElmOrID: "expandedButton", + expectedUtterance: [[{"string": "stateExpanded"}, + {"string": "pushbutton"}, "I am expanded"], ["I am expanded", + {"string": "stateExpanded"}, {"string": "pushbutton"}]], + expectedBraille: [[{"string": "pushbuttonAbbr"}, "I am expanded"], + ["I am expanded", {"string": "pushbuttonAbbr"}]] + }, { + // test collapsed state utterance + accOrElmOrID: "collapsedButton", + expectedUtterance: [[{"string": "stateCollapsed"}, + {"string": "pushbutton"}, "I am collapsed"], ["I am collapsed", + {"string": "stateCollapsed"}, {"string": "pushbutton"}]], + expectedBraille: [[{"string": "pushbuttonAbbr"}, "I am collapsed"], + ["I am collapsed", {"string": "pushbuttonAbbr"}]] + }, { + // test required state utterance + accOrElmOrID: "requiredInput", + expectedUtterance: [[{"string": "stateRequired"}, {"string": "entry"}, + "I am required"], ["I am required", {"string": "stateRequired"}, + {"string": "entry"}]], + expectedBraille: [[{"string": "entryAbbr"}, "I am required"], + ["I am required", {"string": "entryAbbr"}]] + }, { + // test unavailable state utterance on inputs + accOrElmOrID: "readonlyInput", + expectedUtterance: [[{"string": "stateReadonly"}, {"string": "entry"}, + "No edits"], ["No edits", {"string": "stateReadonly"}, + {"string": "entry"}]], + expectedBraille: [[{"string": "entryAbbr"}, "No edits"], + ["No edits", {"string": "entryAbbr"}]] + }, { + // test unavailable state utterance on textareas + accOrElmOrID: "readonlyTextarea", + expectedUtterance: [[{"string": "stateReadonly"}, {"string": "textarea"}, + "No editing"], ["No editing", {"string": "stateReadonly"}, + {"string": "textarea"}]], + expectedBraille: [[{"string": "textareaAbbr"}, "No editing"], + ["No editing", {"string": "textareaAbbr"}]] + }, { + // test has popup state utterance + accOrElmOrID: "hasPopupButton", + expectedUtterance: [[{"string": "stateHasPopup"}, + {"string": "buttonmenu"}, "I have a popup"], ["I have a popup", + {"string": "stateHasPopup"}, {"string": "buttonmenu"}]], + expectedBraille: [[{"string": "buttonmenuAbbr"}, "I have a popup"], + ["I have a popup", {"string": "buttonmenuAbbr"}]] + }, { + // Test selected tab + accOrElmOrID: "tab1", + expectedUtterance: [[{"string": "pagetablist"}, + {"string": "stateSelected"}, {"string": "pagetab"}, + {"string": "objItemOfN", "args": [1, 2]}, "Account"], ["Account", + {"string": "stateSelected"}, {"string": "pagetab"}, + {"string": "objItemOfN", "args": [1, 2]}, {"string": "pagetablist"}] + ], + expectedBraille: [[{"string": "pagetabAbbr"}, + {"string": "objItemOfN", "args": [1, 2]}, "Account"], ["Account", + {"string": "pagetabAbbr"}, + {"string": "objItemOfN", "args": [1, 2]}]] + }, { + // Test unselected tab + accOrElmOrID: "tab2", + expectedUtterance: [[{"string": "pagetablist"}, {"string": "pagetab"}, + {"string": "objItemOfN", "args": [2, 2]}, "Advanced"], ["Advanced", + {"string": "pagetab"}, {"string": "objItemOfN", "args": [2, 2]}, + {"string": "pagetablist"}]], + expectedBraille: [[{"string": "pagetabAbbr"}, + {"string": "objItemOfN", "args": [2, 2]}, "Advanced"], ["Advanced", + {"string": "pagetabAbbr"}, + {"string": "objItemOfN", "args": [2, 2]}]] + }, { + // Landing on this label should mimic landing on the checkbox. + accOrElmOrID: "label1", + expectedUtterance: [[{"string": "stateNotChecked"}, + {"string": "checkbutton"}, "Orange"], ["Orange", + {"string": "stateNotChecked"}, {"string": "checkbutton"}]], + expectedBraille: [[{"string": "stateUncheckedAbbr"}, "Orange"], + ["Orange", {"string": "stateUncheckedAbbr"}]] + }, { + // Here we get a top-level view of the form. + accOrElmOrID: "form1", + expectedUtterance: [[{"string": "label"}, + {"string": "stateNotChecked"}, {"string": "checkbutton"}, "Orange", + "Orange", {"string": "stateNotChecked"}, {"string": "checkbutton"}, + "Blue", {"string": "label"}, "Blue"], ["Orange", + {"string": "stateNotChecked"}, {"string": "checkbutton"}, "Orange", + {"string": "label"}, "Blue", {"string": "stateNotChecked"}, + {"string": "checkbutton"}, "Blue", {"string": "label"}]], + expectedBraille: [[{"string": "labelAbbr"}, + {"string": "stateUncheckedAbbr"}, "Orange", "Orange", + {"string": "stateUncheckedAbbr"}, "Blue", {"string": "labelAbbr"}, + "Blue"], ["Orange", {"string": "stateUncheckedAbbr"}, "Orange", + {"string": "labelAbbr"}, "Blue", {"string": "stateUncheckedAbbr"}, + "Blue", {"string": "labelAbbr"}]] + }, { + // This is a non-nesting label. + accOrElmOrID: "label2", + expectedUtterance: [[{"string": "label"}, "Blue"], + ["Blue", {"string": "label"}]], + expectedBraille: [[{"string": "labelAbbr"}, "Blue"], + ["Blue", {"string": "labelAbbr"}]] + }, { + // This is a distinct control. + accOrElmOrID: "input2", + expectedUtterance: [[{"string": "stateNotChecked"}, + {"string": "checkbutton"}, "Blue"], ["Blue", + {"string": "stateNotChecked"}, {"string": "checkbutton"}]], + expectedBraille: [[{"string": "stateUncheckedAbbr"}, "Blue"], ["Blue", + {"string": "stateUncheckedAbbr"}]] + }, { + // This is a nested control. + accOrElmOrID: "input1", + expectedUtterance: [[{"string": "stateNotChecked"}, + {"string": "checkbutton"}, "Orange"], ["Orange", + {"string": "stateNotChecked"}, {"string": "checkbutton"}]], + expectedBraille: [[{"string": "stateUncheckedAbbr"}, "Orange"], + ["Orange", {"string": "stateUncheckedAbbr"}]] + }, { + // Landing on this label should mimic landing on the entry. + accOrElmOrID: "label3", + expectedUtterance: [[{"string": "entry"}, "Joe", "First name:"], + ["First name:", "Joe", {"string": "entry"}]], + expectedBraille: [[{"string": "entryAbbr"}, "Joe", "First name:"], + ["First name:", "Joe", {"string": "entryAbbr"}]] + }, { + // This is a nested control with a value. + accOrElmOrID: "input3", + expectedUtterance: [[{"string": "entry"}, "Joe", "First name:"], + ["First name:", "Joe", {"string": "entry"}]], + expectedBraille: [[{"string": "entryAbbr"}, "Joe", "First name:"], + ["First name:", "Joe", {"string": "entryAbbr"}]] + }, { + // This is a nested control with a value. + accOrElmOrID: "input4", + expectedUtterance: [[{"string": "slider"}, "3", "Points:"], + ["Points:", "3", {"string": "slider"}]], + expectedBraille: [[{"string": "sliderAbbr"}, "3", "Points:"], + ["Points:", "3", {"string": "sliderAbbr"}]] + }, { + accOrElmOrID: "password", + expectedUtterance: [[{"string": "passwordtext"}, "Secret Password"], + ["Secret Password", {"string": "passwordtext"}]], + expectedBraille: [[{"string": "passwordtextAbbr"}, "Secret Password"], + ["Secret Password", {"string": "passwordtextAbbr"}]] + }, { + accOrElmOrID: "input5", + expectedUtterance: [[{"string": "stateChecked"}, + {"string": "checkbutton"}, "Boring label"], ["Boring label", + {"string": "stateChecked"}, {"string": "checkbutton"}]], + expectedBraille: [[{"string": "stateCheckedAbbr"}, "Boring label"], + ["Boring label", {"string": "stateCheckedAbbr"}]] + }, { + accOrElmOrID: "radio_unselected", + expectedUtterance: [[{"string": "stateNotChecked"}, + {"string": "radiobutton"}, "any old radio button"], + ["any old radio button", {"string": "stateNotChecked"}, + {"string": "radiobutton"}] + ], + expectedBraille: [ + [{"string": "stateUncheckedAbbr"}, "any old radio button"], + ["any old radio button", {"string": "stateUncheckedAbbr"}]] + }, { + accOrElmOrID: "radio_selected", + expectedUtterance: [[{"string": "stateChecked"}, + {"string": "radiobutton"}, "a unique radio button"], + ["a unique radio button", {"string": "stateChecked"}, + {"string": "radiobutton"}]], + expectedBraille: [ + [{"string": "stateCheckedAbbr"}, "a unique radio button"], + ["a unique radio button", {"string": "stateCheckedAbbr"}]] + }, { + accOrElmOrID: "togglebutton_notpressed", + expectedUtterance: [[{"string": "togglebutton"}, "I am not pressed"], + ["I am not pressed", {"string": "togglebutton"}]], + expectedBraille: [ + [{"string": "stateUnpressedAbbr"}, "I am not pressed"], + ["I am not pressed", {"string": "stateUnpressedAbbr"}]] + }, { + accOrElmOrID: "togglebutton_pressed", + expectedUtterance: [[{"string": "statePressed"}, + {"string": "togglebutton"}, "I am pressed!"], ["I am pressed!", + {"string": "statePressed"}, {"string": "togglebutton"}]], + expectedBraille: [[{"string": "statePressedAbbr"}, "I am pressed!"], + ["I am pressed!", {"string": "statePressedAbbr"}]] + }, { + accOrElmOrID: "listbox-option", + expectedUtterance: [[{"string": "listbox"}, + {"string": "listboxoption"}, "Search suggestion"], + ["Search suggestion", {"string": "listboxoption"}, + {"string": "listbox"}] + ], + expectedBraille: [ + [{"string": "listboxoptionAbbr"}, "Search suggestion"], + ["Search suggestion", {"string": "listboxoptionAbbr"}]] + }, { + accOrElmOrID: "listbox-option2", + oldAccOrElmOrID: "listbox-option", + expectedUtterance: [[{"string": "listboxoption"}, "555-12345"], + ["555-12345", {"string": "listboxoption"}]], + expectedBraille: [[{"string": "listboxoptionAbbr"}, "555-12345"], + ["555-12345", {"string": "listboxoptionAbbr"}]] + }, { + accOrElmOrID: "columnheader", + oldAccOrElmOrID: "grid", + expectedUtterance: [[{"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args" :[1]}, "Sunday"], ["Sunday", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args" :[1]}]], + expectedBraille: [[{"string": "cellInfoAbbr", "args": [1, 1]}, + "Sunday"], ["Sunday", {"string": "cellInfoAbbr", "args": [1, 1]}]] + }, { + accOrElmOrID: "rowheader", + oldAccOrElmOrID: "grid", + expectedUtterance: [[{"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "Sunday", "Week 1"], ["Week 1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "Sunday"]], + expectedBraille: [[{"string": "cellInfoAbbr", "args": [1, 2]}, + "Sunday", "Week 1"], ["Week 1", + {"string": "cellInfoAbbr", "args": [1, 2]}, "Sunday"]] + }, { + accOrElmOrID: "gridcell1", + oldAccOrElmOrID: "grid", + expectedUtterance: [["3"], ["3"]], + expectedBraille: [["3"], ["3"]] + }, { + accOrElmOrID: "gridcell2", + oldAccOrElmOrID: "grid", + expectedUtterance: [["4", "7"], ["4", "7"]], + expectedBraille: [["4", "7"], ["4", "7"]] + }, { + accOrElmOrID: "gridcell3", + oldAccOrElmOrID: "grid", + expectedUtterance: [[{"string": "stateSelected"}, "5"], + ["5", {"string": "stateSelected"}]], + expectedBraille: [["5"], ["5"]], + }, { + accOrElmOrID: "frequency", + expectedUtterance: [[{"string": "stateCollapsed"}, + {"string": "stateHasPopup"}, {"string": "combobox"}, "15 min"], [ + "15 min", {"string": "stateCollapsed"}, {"string": "stateHasPopup"}, + {"string": "combobox"}]], + expectedBraille: [[{"string": "comboboxAbbr"}, "15 min"], ["15 min", + {"string": "comboboxAbbr"}]] + }, { + accOrElmOrID: "selected-combobox-option", + oldAccOrElmOrID: "frequency", + expectedUtterance: [[{"string": "stateSelected"}, + {"string": "comboboxoption"}, "15 min"], ["15 min", + {"string": "stateSelected"}, {"string": "comboboxoption"}]], + expectedBraille: [[{"string": "comboboxoptionAbbr"}, "15 min"], [ + "15 min", {"string": "comboboxoptionAbbr"}]] + }, { + accOrElmOrID: "combobox-option", + oldAccOrElmOrID: "frequency", + expectedUtterance: [[{"string": "comboboxoption"}, "30 min"], [ + "30 min", {"string": "comboboxoption"}]], + expectedBraille: [[{"string": "comboboxoptionAbbr"}, "30 min"], [ + "30 min", {"string": "comboboxoptionAbbr"}]] + }, { + accOrElmOrID: "labelled-combobox", + expectedUtterance: [[{"string": "stateCollapsed"}, + {"string": "stateHasPopup"}, {"string": "combobox"}, "Never", + "Intervals"], ["Intervals", "Never", {"string": "stateCollapsed"}, + {"string": "stateHasPopup"}, {"string": "combobox"}]], + expectedBraille: [[{"string": "comboboxAbbr"}, "Never", "Intervals"], + ["Intervals", "Never", {"string": "comboboxAbbr"}]] + }, { + accOrElmOrID: "statusbar-1", + expectedUtterance: [["Last sync:", "2 days ago"], + ["Last sync:", "2 days ago"]], + expectedBraille: [["Last sync:", "2 days ago"], + ["Last sync:", "2 days ago"]] + }, { + accOrElmOrID: "statusbar-2", + expectedUtterance: [["Last sync: 30min ago"], + ["Last sync: 30min ago"]], + expectedBraille: [["Last sync: 30min ago"], ["Last sync: 30min ago"]] + }, { + accOrElmOrID: "switch-1", + expectedUtterance: [[{"string": "stateOn"}, {"string": "switch"}, + "Simple switch"], ["Simple switch", {"string": "stateOn"}, + {"string": "switch"}]], + expectedBraille: [[{"string": "stateCheckedAbbr"}, "Simple switch"], + ["Simple switch", {"string": "stateCheckedAbbr"}]] + }, { + accOrElmOrID: "switch-2", + expectedUtterance: [[{"string": "stateOff"}, + {"string": "switch"}, "Another switch"], ["Another switch", + {"string": "stateOff"}, {"string": "switch"}]], + expectedBraille: [ + [{"string": "stateUncheckedAbbr"}, "Another switch"], + ["Another switch", {"string": "stateUncheckedAbbr"}]] + }]; + + // Test all possible utterance order preference values. + function testOutputOrder(aOutputOrder) { + return function() { + SpecialPowers.pushPrefEnv({ + "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]] + }, function() { + tests.forEach(function run(test) { + testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 1); + testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 0); + }); + AccessFuTest.nextTest(); + }); + }; + } + + AccessFuTest.addFunc(testOutputOrder(0)); + AccessFuTest.addFunc(testOutputOrder(1)); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + + </script> + </head> + <body> + <div id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=753984" + title="[AccessFu] utterance order test"> + Mozilla Bug 753984</a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=758675" + title="[AccessFu] Add support for accDescription"> + Mozilla Bug 758675</a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=876475" + title="[AccessFu] Make braille output less verbose"> + Mozilla Bug 876475</a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=924284" + title="[AccessFu] Output accessible values"> + Mozilla Bug 924284</a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=925845" + title="[AccessFu] Unify output tests"> + Mozilla Bug 925845</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + <a id="anchor" href="#test" title="title"></a> + <a id="anchor_titleandtext" href="#test" title="goes to the tests">Tests</a> + <a id="anchor_duplicatedtitleandtext" href="#test" title="Tests">Tests</a> + <a id="anchor_arialabelandtext" href="#test" aria-label="Tests" title="goes to the tests">Tests</a> + <textarea id="textarea" cols="80" rows="5"> + This is the text area text. + </textarea> + <h1 id="heading" title="Test heading"></h1> + <ol id="list"> + <li id="li_one">list one</li> + </ol> + <ul id="unorderd_list"> + <li id="li_two">list two</li> + </ul> + <dl id="dlist"> + <dd id="dd_one"> + dd one + </dd> + </dl> + <table> + <caption>Fruits and vegetables</caption> + <tr> + <td id="cell"> + <ul style="list-style-type: none;"> + <li><a id="apples" href="#">Apples</a></li> + <li><a id="bananas" href="#">Bananas</a></li> + <li><a href="#">Peaches</a></li> + <li> + <a href="#"> + Plums + </a> + </li> + </ul> + </td> + </tr> + </table> + <button id="unavailableButton" disabled>I am unavailable</button> + <button id="expandedButton" aria-expanded="true">I am expanded</button> + <button id="collapsedButton" aria-expanded="false">I am collapsed</button> + <input id="requiredInput" required placeholder="I am required" /> + <input id="readonlyInput" readonly value="No edits" /> + <textarea id="readonlyTextarea" readonly>No editing</textarea> + <button id="hasPopupButton" aria-haspopup="true">I have a popup</button> + <div role="tablist"> + <a id="tab1" href="#" role="tab" aria-selected="true">Account</a> + <a id="tab2" href="#" role="tab" aria-selected="false">Advanced</a> + </div> + <form id="form1"> + <label id="label1"><input id="input1" type="checkbox">Orange</label> + <input id="input2" type="checkbox"><label id="label2" for="input2">Blue</label> + </form> + <label id="label3">First name: <input id="input3" value="Joe"></label> + <label id="label4">Points: + <input id="input4" type="range" name="points" min="1" max="10" value="3"> + </label> + <label for="input5">Boring label</label><input id="input5" type="checkbox" checked></input> + <label for="password">Secret Password</label><input id="password" type="password"></input> + <label for="radio_unselected">any old radio button</label><input id="radio_unselected" type="radio"></input> + <label for="radio_selected">a unique radio button</label><input id="radio_selected" type="radio" checked></input> + <input id="date" type="date" value="2011-09-29" /> + <input id="email" type="email" value="test@example.com" /> + <input id="search" type="search" value="This is a search" /> + <input id="tel" type="tel" value="555-5555" /> + <input id="url" type="url" value="http://example.com" /> + <input id="textInput" type="text" value="This is text." /> + <label>Points: <input id="range" type="range" name="points" min="1" max="10" value="3"></label> + <div id="togglebutton_notpressed" aria-pressed="false" role="button" tabindex="-1">I am not pressed</div> + <div id="togglebutton_pressed" aria-pressed="true" role="button" tabindex="-1">I am pressed!</div> + <ul role="listbox" style="list-style-type: none;"> + <li role="option" id="listbox-option">Search suggestion</li> + <li role="option" id="listbox-option2"> + <label aria-hidden="true"> + <input type="checkbox" /> + </label> + 555-12345 + </li> + </ul> + <section id="grid" role="grid"> + <ol role="row"> + <li role="presentation"></li> + <li id="columnheader" role="columnheader" aria-label="Sunday">S</li> + <li role="columnheader">M</li> + </ol> + <ol role="row"> + <li id="rowheader" role="rowheader" aria-label="Week 1">1</li> + <li id="gridcell1" role="gridcell"><span>3</span><div></div></li> + <li id="gridcell2" role="gridcell"><span>4</span><div>7</div></li> + </ol> + <ol role="row"> + <li role="rowheader">2</li> + <li id="gridcell3" aria-selected="true" role="gridcell">5</li> + <li role="gridcell">6</li> + </ol> + </section> + <select id="frequency"> + <option id="selected-combobox-option" value="15">15 min</option> + <option id="combobox-option" value="30">30 min</option> + <option value="null">Manual</option> + </select> + <select id="labelled-combobox" aria-label="Intervals"> + <option value="15">Every 15 min</option> + <option value="30">Every 30 min</option> + <option value="null" selected>Never</option> + </select> + <div id="statusbar-1" role="status">Last sync:<span>2 days ago</span></div> + <div aria-label="Last sync: 30min ago" id="statusbar-2" role="status">I should be ignored</div> + <span id="switch-1" role="switch" aria-label="Simple switch" aria-checked="true"></span> + <span id="switch-2" role="switch" aria-label="Another switch" aria-checked="false"></span> + </div> + </body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_output_mathml.html b/accessible/tests/mochitest/jsat/test_output_mathml.html new file mode 100644 index 000000000..3fe4779b2 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_output_mathml.html @@ -0,0 +1,313 @@ +<html> +<head> + <title>[AccessFu] MathML Accessibility Support</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="output.js"></script> + <script type="application/javascript" + src="jsatcommon.js"></script> + <script type="application/javascript"> + + function doTest() { + // Test the following accOrElmOrID. + var tests = [{ + accOrElmOrID: "math-1", + expectedUtterance: [ + [{"string":"open-fence"},"(","x",",","y",{"string":"close-fence"},")"], + ["(",{"string":"open-fence"},"x",",","y",")",{"string":"close-fence"}] + ], + expectedBraille: [ + [{"string":"open-fenceAbbr"},"(","x",",","y",{"string":"close-fenceAbbr"},")"], + ["(",{"string":"open-fenceAbbr"},"x",",","y",")",{"string":"close-fenceAbbr"}] + ] + }, { + accOrElmOrID: "mfrac-1", + expectedUtterance: [ + [{"string":"mathmlfraction"},{"string":"numerator"},"a",{"string":"denominator"},"b"], + ["a",{"string":"numerator"},"b",{"string":"denominator"},{"string":"mathmlfraction"}] + ], + expectedBraille: [ + [{"string":"mathmlfractionAbbr"},{"string":"numeratorAbbr"},"a",{"string":"denominatorAbbr"},"b"], + ["a",{"string":"numeratorAbbr"},"b",{"string":"denominatorAbbr"},{"string":"mathmlfractionAbbr"}] + ] + }, { + accOrElmOrID: "mfrac-2", + expectedUtterance: [ + [{"string":"mathmlfractionwithoutbar"},{"string":"numerator"},"a",{"string":"denominator"},"b"], + ["a",{"string":"numerator"},"b",{"string":"denominator"},{"string":"mathmlfractionwithoutbar"}] + ], + expectedBraille: [ + [{"string":"mathmlfractionwithoutbarAbbr"},{"string":"numeratorAbbr"},"a",{"string":"denominatorAbbr"},"b"], + ["a",{"string":"numeratorAbbr"},"b",{"string":"denominatorAbbr"},{"string":"mathmlfractionwithoutbarAbbr"}] + ] + }, { + accOrElmOrID: "msub-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b"], + ["a",{"string":"base"},"b",{"string":"subscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b"], + ["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "msup-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"superscript"},"b"], + ["a",{"string":"base"},"b",{"string":"superscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"superscriptAbbr"},"b"], + ["a",{"string":"baseAbbr"},"b",{"string":"superscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "msubsup-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b",{"string":"superscript"},"c"], + ["a",{"string":"base"},"b",{"string":"subscript"},"c",{"string":"superscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b",{"string":"superscriptAbbr"},"c"], + ["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},"c",{"string":"superscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "mmultiscripts-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b",{"string":"superscript"},"c",{"string":"superscript"},"d",{"string":"presubscript"},"e",{"string":"presubscript"},"f",{"string":"presuperscript"},"g"], + ["a",{"string":"base"},"b",{"string":"subscript"},"c",{"string":"superscript"},"d",{"string":"superscript"},"e",{"string":"presubscript"},"f",{"string":"presubscript"},"g",{"string":"presuperscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b",{"string":"superscriptAbbr"},"c",{"string":"superscriptAbbr"},"d",{"string":"presubscriptAbbr"},"e",{"string":"presubscriptAbbr"},"f",{"string":"presuperscriptAbbr"},"g"], + ["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},"c",{"string":"superscriptAbbr"},"d",{"string":"superscriptAbbr"},"e",{"string":"presubscriptAbbr"},"f",{"string":"presubscriptAbbr"},"g",{"string":"presuperscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "munder-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"underscript"},"b"], + ["a",{"string":"base"},"b",{"string":"underscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"underscriptAbbr"},"b"], + ["a",{"string":"baseAbbr"},"b",{"string":"underscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "mover-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"overscript"},"b"], + ["a",{"string":"base"},"b",{"string":"overscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"overscriptAbbr"},"b"], + ["a",{"string":"baseAbbr"},"b",{"string":"overscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "munderover-1", + expectedUtterance: [ + [{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"underscript"},"b",{"string":"overscript"},"c"], + ["a",{"string":"base"},"b",{"string":"underscript"},"c",{"string":"overscript"},{"string":"mathmlscripted"}] + ], + expectedBraille: [ + [{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"underscriptAbbr"},"b",{"string":"overscriptAbbr"},"c"], + ["a",{"string":"baseAbbr"},"b",{"string":"underscriptAbbr"},"c",{"string":"overscriptAbbr"},{"string":"mathmlscriptedAbbr"}] + ] + }, { + accOrElmOrID: "mroot-1", + expectedUtterance: [ + [{"string":"mathmlroot"},{"string":"base"},"a",{"string":"root-index"},"b"], + ["a",{"string":"base"},"b",{"string":"root-index"},{"string":"mathmlroot"}] + ], + expectedBraille: [ + [{"string":"mathmlrootAbbr"},{"string":"baseAbbr"},"a",{"string":"root-indexAbbr"},"b"], + ["a",{"string":"baseAbbr"},"b",{"string":"root-indexAbbr"},{"string":"mathmlrootAbbr"}] + ] + }, { + accOrElmOrID: "mtable-1", + expectedUtterance: [ + [{"string":"mathmltable"},{"string":"tblColumnInfo","count":3},{"string":"tblRowInfo","count":2},{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[1]},"a",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[1]},"b",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[1]},"c",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[2]},"d",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[2]},"e",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[2]},"f"], + ["a",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[1]},"b",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[1]},"c",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[1]},"d",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[2]},"e",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[2]},"f",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[2]},{"string":"mathmltable"},{"string":"tblColumnInfo","count":3},{"string":"tblRowInfo","count":2}] + ], + expectedBraille: [ + [{"string":"mathmltableAbbr"},{"string":"tblColumnInfoAbbr","count":3},{"string":"tblRowInfoAbbr","count":2},{"string":"cellInfoAbbr","args":[1,1]},"a",{"string":"cellInfoAbbr","args":[2,1]},"b",{"string":"cellInfoAbbr","args":[3,1]},"c",{"string":"cellInfoAbbr","args":[1,2]},"d",{"string":"cellInfoAbbr","args":[2,2]},"e",{"string":"cellInfoAbbr","args":[3,2]},"f"], + ["a",{"string":"cellInfoAbbr","args":[1,1]},"b",{"string":"cellInfoAbbr","args":[2,1]},"c",{"string":"cellInfoAbbr","args":[3,1]},"d",{"string":"cellInfoAbbr","args":[1,2]},"e",{"string":"cellInfoAbbr","args":[2,2]},"f",{"string":"cellInfoAbbr","args":[3,2]},{"string":"mathmltableAbbr"},{"string":"tblColumnInfoAbbr","count":3},{"string":"tblRowInfoAbbr","count":2}] + ] + }, { + accOrElmOrID: "menclose-1", + expectedUtterance: [ + [{"string":"mathmlenclosed"},{"string":"notation-longdiv"},"a"], + ["a",{"string":"notation-longdiv"},{"string":"mathmlenclosed"}] + ], + expectedBraille: [ + [{"string":"mathmlenclosedAbbr"},{"string":"notation-longdivAbbr"},"a"], + ["a",{"string":"notation-longdivAbbr"},{"string":"mathmlenclosedAbbr"}] + ] + }, { + accOrElmOrID: "menclose-2", + expectedUtterance: [ + [{"string":"mathmlenclosed"},{"string":"notation-circle"},"a"], + ["a",{"string":"notation-circle"},{"string":"mathmlenclosed"}] + ], + expectedBraille: [ + [{"string":"mathmlenclosedAbbr"},{"string":"notation-circleAbbr"},"a"], + ["a",{"string":"notation-circleAbbr"},{"string":"mathmlenclosedAbbr"}] + ] + }, { + accOrElmOrID: "menclose-3", + expectedUtterance: [ + [{"string":"mathmlenclosed"},{"string":"notation-left"},{"string":"notation-top"},{"string":"notation-bottom"},"a"], + ["a",{"string":"notation-left"},{"string":"notation-top"},{"string":"notation-bottom"},{"string":"mathmlenclosed"}] + ], + expectedBraille: [ + [{"string":"mathmlenclosedAbbr"},{"string":"notation-leftAbbr"},{"string":"notation-topAbbr"},{"string":"notation-bottomAbbr"},"a"], + ["a",{"string":"notation-leftAbbr"},{"string":"notation-topAbbr"},{"string":"notation-bottomAbbr"},{"string":"mathmlenclosedAbbr"}] + ] + }]; + + // Test all possible utterance order preference values. + function testOutputOrder(aOutputOrder) { + return function() { + SpecialPowers.pushPrefEnv({ + "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]] + }, function() { + tests.forEach(function run(test) { + testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 1); + testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 0); + }); + AccessFuTest.nextTest(); + }); + }; + } + + AccessFuTest.addFunc(testOutputOrder(0)); + AccessFuTest.addFunc(testOutputOrder(1)); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + <div id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1163374" + title="[AccessFu] MathML Accessibility Support"> + Mozilla Bug 1163374 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + + <math id="math-1"><mo>(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>)</mo></math> + + <math> + <mfrac id="mfrac-1"> + <mi>a</mi> + <mi>b</mi> + </mfrac> + </math> + + <math> + <mfrac id="mfrac-2" linethickness="0px"> + <mi>a</mi> + <mi>b</mi> + </mfrac> + </math> + + <math> + <msub id="msub-1"> + <mi>a</mi> + <mi>b</mi> + </msub> + </math> + <math> + <msup id="msup-1"> + <mi>a</mi> + <mi>b</mi> + </msup> + </math> + <math> + <msubsup id="msubsup-1"> + <mi>a</mi> + <mi>b</mi> + <mi>c</mi> + </msubsup> + </math> + <math> + <mmultiscripts id="mmultiscripts-1"> + <mi>a</mi> + <mi>b</mi> + <mi>c</mi> + <none/> + <mi>d</mi> + <mprescripts/> + <mi>e</mi> + <none/> + <mi>f</mi> + <mi>g</mi> + </mmultiscripts> + </math> + + <math> + <munder id="munder-1"> + <mi>a</mi> + <mi>b</mi> + </munder> + </math> + <math> + <mover id="mover-1"> + <mi>a</mi> + <mi>b</mi> + </mover> + </math> + <math> + <munderover id="munderover-1"> + <mi>a</mi> + <mi>b</mi> + <mi>c</mi> + </munderover> + </math> + + <math> + <mroot id="mroot-1"> + <mi>a</mi> + <mi>b</mi> + </mroot> + </math> + + <math> + <mtable id="mtable-1"> + <mtr> + <mtd><mi>a</mi></mtd> + <mtd><mi>b</mi></mtd> + <mtd><mi>c</mi></mtd> + </mtr> + <mtr> + <mtd><mi>d</mi></mtd> + <mtd><mi>e</mi></mtd> + <mtd><mi>f</mi></mtd> + </mtr> + </mtable> + </math> + + <math> + <menclose id="menclose-1"><mi>a</mi></menclose> + </math> + <math> + <menclose id="menclose-2" notation="circle"><mi>a</mi></menclose> + </math> + <math> + <menclose id="menclose-3" notation="left top bottom"><mi>a</mi></menclose> + </math> + + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_pointer_relay.html b/accessible/tests/mochitest/jsat/test_pointer_relay.html new file mode 100644 index 000000000..cb58fe73b --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_pointer_relay.html @@ -0,0 +1,95 @@ +<html> + +<head> + <title>AccessFu tests for pointer relay.</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../common.js"></script> + <script type="application/javascript" src="../layout.js"></script> + <script type="application/javascript" src="./jsatcommon.js"></script> + <script type="application/javascript" src="./dom_helper.js"></script> + <script type="application/javascript"> + + Components.utils.import( + "resource://gre/modules/accessibility/PointerAdapter.jsm"); + + var tests = [ + { + type: 'touchstart', target: [{base: 'button'}], + expected: {type: 'pointerdown', length: 1} + }, + { + type: 'touchmove', target: [{base: 'button'}], + expected: {type: 'pointermove', length: 1} + }, + { + type: 'touchend', target: [{base: 'button'}], + expected: {type: 'pointerup'} + }, + { + type: 'touchstart', target: [{base: 'button'}, + {base: 'button', x: 0.5, y: 0.3}], + expected: {type: 'pointerdown', length: 2} + }, + { + type: 'touchend', target: [{base: 'button'}, + {base: 'button', x: 0.5, y: 0.3}], + expected: {type: 'pointerup'} + }, + { + type: 'touchstart', target: [{base: 'button'}, + {base: 'button', x: 0.5, y: 0.3}, + {base: 'button', x: 0.5, y: -0.3}], + expected: {type: 'pointerdown', length: 3} + }, + { + type: 'touchend', target: [{base: 'button'}, + {base: 'button', x: 0.5, y: 0.3}, + {base: 'button', x: 0.5, y: -0.3}], + expected: {type: 'pointerup'} + } + ]; + + function makeTestFromSpec(test) { + return function runTest() { + PointerRelay.start(function onPointerEvent(aDetail) { + is(aDetail.type, test.expected.type, + 'mozAccessFuPointerEvent is correct.'); + if (test.expected.length) { + is(aDetail.points.length, test.expected.length, + 'mozAccessFuPointerEvent points length is correct.'); + } + PointerRelay.stop(); + AccessFuTest.nextTest(); + }); + eventMap[test.type](test.target, test.type); + }; + } + + function doTest() { + tests.forEach(function addTest(test) { + AccessFuTest.addFunc(makeTestFromSpec(test)); + }); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> +<body id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=976082" + title="[AccessFu] Provide tests for pointer relay."> + Mozilla Bug 981015 + </a> + <div> + <button id="button">I am a button</button> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_quicknav_modes.html b/accessible/tests/mochitest/jsat/test_quicknav_modes.html new file mode 100644 index 000000000..f99b64a84 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html @@ -0,0 +1,107 @@ +<html> + +<head> + <title>AccessFu test for enabling</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="./jsatcommon.js"></script> + <script type="application/javascript"> + + function prefStart() { + // Start AccessFu via pref. + SpecialPowers.pushPrefEnv({"set": [['accessibility.accessfu.activate', 1]]}); + AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest); + } + + function nextMode(aCurrentMode, aNextMode) { + return function() { + is(AccessFu.Input.quickNavMode.current, aCurrentMode, + 'initial current mode is correct'); + AccessFu.Input.quickNavMode.next(); + _expectMode(aNextMode, AccessFuTest.nextTest); + } + } + + function prevMode(aCurrentMode, aNextMode) { + return function() { + is(AccessFu.Input.quickNavMode.current, aCurrentMode, + 'initial current mode is correct'); + AccessFu.Input.quickNavMode.previous(); + _expectMode(aNextMode, AccessFuTest.nextTest); + } + } + + function setMode(aModeIndex, aExpectedMode) { + return function() { + SpecialPowers.pushPrefEnv( + {"set": [['accessibility.accessfu.quicknav_index', aModeIndex]]}, + function() { + _expectMode(aExpectedMode, AccessFuTest.nextTest); + }); + } + } + + function reconfigureModes() { + SpecialPowers.pushPrefEnv( + {"set": [['accessibility.accessfu.quicknav_modes', 'Landmark,Button,Entry,Graphic']]}, + function() { + // When the modes are reconfigured, the current mode should + // be set to the first in the new list. + _expectMode('Landmark', AccessFuTest.nextTest); + }); + } + + function _expectMode(aExpectedMode, aCallback) { + if (AccessFu.Input.quickNavMode.current === aExpectedMode) { + ok(true, 'correct mode'); + aCallback(); + } else { + AccessFuTest.once_log('Quicknav mode: ' + aExpectedMode, function() { + ok(true, 'correct mode'); + aCallback(); + }); + } + } + + // Listen for initial 'EventManager.start' and disable AccessFu. + function prefStop() { + ok(AccessFu._enabled, "AccessFu was started via preference."); + AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish()); + SpecialPowers.pushPrefEnv({"set": [['accessibility.accessfu.activate', 0]]}); + } + + function doTest() { + AccessFuTest.addFunc(prefStart); + AccessFuTest.addFunc(nextMode('Link', 'Heading')); + AccessFuTest.addFunc(nextMode('Heading', 'FormElement')); + AccessFuTest.addFunc(nextMode('FormElement', 'Link')); + AccessFuTest.addFunc(nextMode('Link', 'Heading')); + AccessFuTest.addFunc(prevMode('Heading', 'Link')); + AccessFuTest.addFunc(prevMode('Link', 'FormElement')); + AccessFuTest.addFunc(setMode(1, 'Heading')); + AccessFuTest.addFunc(reconfigureModes); + AccessFuTest.addFunc(prefStop); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests([ // Will call SimpleTest.finish(); + ['accessibility.accessfu.quicknav_modes', 'Link,Heading,FormElement']]); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> +<body> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307" + title="[AccessFu] Add mochitest for enabling"> + Mozilla Bug 811307 + </a> +</body> +</html>
\ No newline at end of file diff --git a/accessible/tests/mochitest/jsat/test_tables.html b/accessible/tests/mochitest/jsat/test_tables.html new file mode 100644 index 000000000..aa7f482e9 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_tables.html @@ -0,0 +1,579 @@ +<html> +<head> + <title>[AccessFu] Improve reading of table semantics</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="output.js"></script> + <script type="application/javascript" + src="jsatcommon.js"></script> + <script type="application/javascript"> + + function doTest() { + // Test the following accOrElmOrID. + var tests = [{ + accOrElmOrID: "table1", + expectedUtterance: [[ + {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "col1", "cell1", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2", "cell2"], ["col1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "cell1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "col1", "cell2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2", {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}]], + expectedBraille: [[ + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 2}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [1, 1]}, "col1", + {"string": "cellInfoAbbr", "args": [2, 1]}, "col2", + {"string": "cellInfoAbbr", "args": [1, 2]}, "col1", "cell1", + {"string": "cellInfoAbbr", "args": [2, 2]}, "col2", "cell2"], ["col1", + {"string": "cellInfoAbbr", "args": [1, 1]}, "col2", + {"string": "cellInfoAbbr", "args": [2, 1]}, "cell1", + {"string": "cellInfoAbbr", "args": [1, 2]}, "col1", "cell2", + {"string": "cellInfoAbbr", "args": [2, 2]}, "col2", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 2}, + {"string": "tblRowInfoAbbr", "count": 2}]] + }, { + accOrElmOrID: "table2", + expectedUtterance: [[ + {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1", "cell1", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "colheader", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", "bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "col1", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2"], ["cell1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1", "colheader", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", "col1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "col2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}]], + expectedBraille: [[{"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 2}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [1, 1]}, "col1", "cell1", + {"string": "cellInfoAbbr", "args": [2, 1]}, "col2", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 1}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [1, 1]}, "colheader", + {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", "bla", + {"string": "cellInfoAbbr", "args": [1, 2]}, "col1", + {"string": "cellInfoAbbr", "args": [2, 2]}, "col2"], ["cell1", + {"string": "cellInfoAbbr", "args": [1, 1]}, "col1", "colheader", + {"string": "cellInfoAbbr", "args": [1, 1]}, "bla", + {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 1}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [2, 1]}, "col2", "col1", + {"string": "cellInfoAbbr", "args": [1, 2]}, "col2", + {"string": "cellInfoAbbr", "args": [2, 2]}, + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 2}, + {"string": "tblRowInfoAbbr", "count": 2}]] + }, { + accOrElmOrID: "table3", + expectedUtterance: [[ + {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "colheader", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", "bla"], ["colheader", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}]], + expectedBraille: [[ + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 1}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [1, 1]}, "colheader", + {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", "bla"], + ["colheader", + {"string": "cellInfoAbbr", "args": [1, 1]}, "bla", + {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 1}, + {"string": "tblRowInfoAbbr", "count": 2}]] + }, { + accOrElmOrID: "table4", + expectedUtterance: [[ + {"string": "table"}, + {"string": "tblColumnInfo", "count": 4}, + {"string": "tblRowInfo", "count": 3}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [1]}, "col3", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, + {"string": "spansColumns", "args": [2]}, "col1", "row1", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [2]}, "col3", "row1", "cell1", + {"string": "columnInfo", "args": [4]}, + {"string": "rowInfo", "args": [2]}, + {"string": "spansRows", "args": [2]}, "row1", "cell2", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [3]}, "col1", "row2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [3]}, "col2", "row2", "cell3", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [3]}, "col3", "row2", "cell4"], ["col1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col3", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [1]}, "row1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, + {"string": "spansColumns", "args": [2]}, "col1", "cell1", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [2]}, "col3", "row1", "cell2", + {"string": "columnInfo", "args": [4]}, + {"string": "rowInfo", "args": [2]}, + {"string": "spansRows", "args": [2]}, "row1", "row2", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [3]}, "col1", "cell3", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [3]}, "col2", "row2", "cell4", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [3]}, "col3", "row2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 4}, + {"string": "tblRowInfo", "count": 3}]], + expectedBraille: [[ + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 4}, + {"string": "tblRowInfoAbbr", "count": 3}, + {"string": "cellInfoAbbr", "args": [1, 1]}, "col1", + {"string": "cellInfoAbbr", "args": [2, 1]}, "col2", + {"string": "cellInfoAbbr", "args": [3, 1]}, "col3", + {"string": "cellInfoAbbr", "args": [1, 2]}, "col1", "row1", + {"string": "cellInfoAbbr", "args": [3, 2]}, "col3", "row1", "cell1", + {"string": "cellInfoAbbr", "args": [4, 2]}, "row1", "cell2", + {"string": "cellInfoAbbr", "args": [1, 3]}, "col1", "row2", + {"string": "cellInfoAbbr", "args": [2, 3]}, "col2", "row2", "cell3", + {"string": "cellInfoAbbr", "args": [3, 3]}, "col3", "row2", "cell4"], + ["col1", + {"string": "cellInfoAbbr", "args": [1, 1]}, "col2", + {"string": "cellInfoAbbr", "args": [2, 1]}, "col3", + {"string": "cellInfoAbbr", "args": [3, 1]}, "row1", + {"string": "cellInfoAbbr", "args": [1, 2]}, "col1", "cell1", + {"string": "cellInfoAbbr", "args": [3, 2]}, "col3", "row1", "cell2", + {"string": "cellInfoAbbr", "args": [4, 2]}, "row1", "row2", + {"string": "cellInfoAbbr", "args": [1, 3]}, "col1", "cell3", + {"string": "cellInfoAbbr", "args": [2, 3]}, "col2", "row2", "cell4", + {"string": "cellInfoAbbr", "args": [3, 3]}, "col3", "row2", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 4}, + {"string": "tblRowInfoAbbr", "count": 3}]] + }, { + accOrElmOrID: "table5", + expectedUtterance: [["Row1", "Row2"], ["Row1", "Row2"]], + expectedBraille: [["Row1", "Row2"], ["Row1", "Row2"]] + }, { + // Test pivot to table1_th1 from table1. + accOrElmOrID: "table1_th1", + oldAccOrElmOrID: "table1", + expectedUtterance: [[ + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1"], ["col1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}]], + expectedBraille: [[ + {"string": "cellInfoAbbr", "args": [1, 1]}, "col1"], ["col1", + {"string": "cellInfoAbbr", "args": [1, 1]}]] + }, { + // Test pivot to table1_td2 from table1. + accOrElmOrID: "table1_td2", + oldAccOrElmOrID: "table1", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2", "cell2"], ["cell2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [2, 2]}, "col2", "cell2"], + ["cell2", {"string": "cellInfoAbbr", "args": [2, 2]}, "col2"]] + }, { + // Test pivot to table1_td2 from table1_th1. + accOrElmOrID: "table1_td2", + oldAccOrElmOrID: "table1_th1", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2", "cell2"], ["cell2", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [2]}, "col2"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [2, 2]}, "col2", "cell2"], + ["cell2", {"string": "cellInfoAbbr", "args": [2, 2]}, "col2"]] + }, { + // Test pivot to table1_td2 from table1_td1. + accOrElmOrID: "table1_td2", + oldAccOrElmOrID: "table1_td1", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, "col2", "cell2"], ["cell2", + {"string": "columnInfo", "args": [2]}, "col2"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [2, 2]}, "col2", "cell2"], + ["cell2", {"string": "cellInfoAbbr", "args": [2, 2]}, "col2"]] + }, { + // Test pivot to table2_cell_1 from table2. + accOrElmOrID: "table2_cell_1", + oldAccOrElmOrID: "table2", + expectedUtterance: [[ + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1", "cell1"], ["cell1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "col1"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 1]}, "col1", "cell1"], + ["cell1", {"string": "cellInfoAbbr", "args": [1, 1]}, "col1"]] + }, { + // Test pivot to table2_cell_2 from table2. + accOrElmOrID: "table2_cell_2", + oldAccOrElmOrID: "table2", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "colheader", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", "bla"], ["colheader", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [1]}, "bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2"]], + expectedBraille: [[ + {"string": "cellInfoAbbr", "args": [2, 1]}, "col2", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 1}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [1, 1]}, "colheader", + {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", "bla"], + ["colheader", + {"string": "cellInfoAbbr", "args": [1, 1]}, "bla", + {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", + {"string": "tableAbbr"}, + {"string": "tblColumnInfoAbbr", "count": 1}, + {"string": "tblRowInfoAbbr", "count": 2}, + {"string": "cellInfoAbbr", "args": [2, 1]}, "col2"]] + }, { + // Test pivot to table2_cell_1 from table2_cell_2. + accOrElmOrID: "table2_cell_1", + oldAccOrElmOrID: "table2_cell_2", + expectedUtterance: [[ + {"string": "columnInfo", "args": [1]}, "col1", "cell1"], ["cell1", + {"string": "columnInfo", "args": [1]}, "col1"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 1]}, "col1", "cell1"], + ["cell1", {"string": "cellInfoAbbr", "args": [1, 1]}, "col1"]] + }, { + // Test pivot to table3_cell from table2. + accOrElmOrID: "table3_cell", + oldAccOrElmOrID: "table2", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", "bla"], ["bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", "bla"], + ["bla", {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader"]] + }, { + // Test pivot to table3_cell from table2_cell_1. + accOrElmOrID: "table3_cell", + oldAccOrElmOrID: "table2_cell_1", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", "bla"], ["bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", "bla"], + ["bla", {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader"]] + }, { + // Test pivot to table3_cell from table3_ch. + accOrElmOrID: "table3_cell", + oldAccOrElmOrID: "table3_ch", + expectedUtterance: [[ + {"string": "rowInfo", "args": [2]}, "bla"], ["bla", + {"string": "rowInfo", "args": [2]}]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 2]}, "bla"], + ["bla", {"string": "cellInfoAbbr", "args": [1, 2]}]] + }, { + // Test pivot to table3_cell from table1_td1. + accOrElmOrID: "table3_cell", + oldAccOrElmOrID: "table1_td1", + expectedUtterance: [[ + {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", "bla"], ["bla", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, "colheader", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 1}, + {"string": "tblRowInfo", "count": 2}, + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [1]}, "col2", + {"string": "table"}, + {"string": "tblColumnInfo", "count": 2}, + {"string": "tblRowInfo", "count": 2}]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 2]}, "colheader", "bla"], + ["bla", {"string": "cellInfoAbbr", "args": [1, 2]}, "colheader"]] + }, { + // Test pivot to table4_ch_3 from table4. + accOrElmOrID: "table4_ch_3", + oldAccOrElmOrID: "table4", + expectedUtterance: [[ + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [1]}, "col3"], ["col3", + {"string": "columnInfo", "args": [3]}, + {"string": "rowInfo", "args": [1]}]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [3, 1]}, "col3"], + ["col3", {"string": "cellInfoAbbr", "args": [3, 1]}]] + }, { + // Test pivot to table4_rh_1 from table4_ch_3. + accOrElmOrID: "table4_rh_1", + oldAccOrElmOrID: "table4_ch_3", + expectedUtterance: [[ + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, + {"string": "spansColumns", "args": [2]}, "col1", "row1"], ["row1", + {"string": "columnInfo", "args": [1]}, + {"string": "rowInfo", "args": [2]}, + {"string": "spansColumns", "args": [2]}, "col1"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [1, 2]}, "col1", "row1"], + ["row1", {"string": "cellInfoAbbr", "args": [1, 2]}, "col1"]] + }, { + // Test pivot to table4_cell_3 from table4_rh_1. + accOrElmOrID: "table4_cell_3", + oldAccOrElmOrID: "table4_rh_1", + expectedUtterance: [[ + {"string": "columnInfo", "args": [4]}, + {"string": "spansRows", "args": [2]}, "cell2"], ["cell2", + {"string": "columnInfo", "args": [4]}, + {"string": "spansRows", "args": [2]}]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [4, 2]}, "cell2"], + ["cell2", {"string": "cellInfoAbbr", "args": [4, 2]}]] + }, { + // Test pivot to table4_cell_5 from table4_cell_3. + accOrElmOrID: "table4_cell_5", + oldAccOrElmOrID: "table4_cell_3", + expectedUtterance: [[ + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [3]}, "col2", "row2", "cell3"], + ["cell3", + {"string": "columnInfo", "args": [2]}, + {"string": "rowInfo", "args": [3]}, "col2", "row2"]], + expectedBraille: [ + [{"string": "cellInfoAbbr", "args": [2, 3]}, "col2", "row2", "cell3"], + ["cell3", {"string": "cellInfoAbbr", "args": [2, 3]}, "col2", "row2"]] + }]; + + // Test outputs (utterance and braille) for tables including their + // headers and cells. + function testOutputOrder(aOutputOrder) { + return function() { + SpecialPowers.pushPrefEnv({ + "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]] + }, function() { + tests.forEach(function run(test) { + testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 1); + testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID, + test.oldAccOrElmOrID, 0); + }); + AccessFuTest.nextTest(); + }); + }; + } + + AccessFuTest.addFunc(testOutputOrder(0)); + AccessFuTest.addFunc(testOutputOrder(1)); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + <div id="root"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=830748" + title="[AccessFu] Improve reading of table semantics"> + Mozilla Bug 830748 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + <table id="table1"> + <thead> + <tr> + <th id="table1_th1">col1</th> + <th>col2</th> + </tr> + </thead> + <tbody> + <tr> + <td id="table1_td1">cell1</td> + <td id="table1_td2">cell2</td> + </tr> + </tbody> + </table> + <table id="table2" border="1"> + <tr> + <td id="table2_cell_1" headers="table2_ch_1">cell1</td> + <td id="table2_cell_2" headers="table2_ch_2"> + <table id="table3"> + <thead> + <tr> + <th id="table3_ch">colheader</th> + </tr> + </thead> + <tbody> + <tr> + <td id="table3_cell">bla</td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td id="table2_ch_1" scope="col">col1</td> + <td id="table2_ch_2" scope="col">col2</td> + </tr> + </table> + <table id="table4" border="1"> + <thead> + <tr> + <th id="table4_ch_1">col1</th> + <th id="table4_ch_2">col2</th> + <td id="table4_ch_3" scope="col">col3</td> + </tr> + </thead> + <tbody> + <tr> + <th id="table4_rh_1" colspan="2">row1</th> + <td id="table4_cell_2">cell1</td> + <td id="table4_cell_3" rowspan="2">cell2</td> + </tr> + <tr> + <td id="table4_rh_2" scope="row">row2</td> + <td id="table4_cell_5">cell3</td> + <td id="table4_cell_6">cell4</td> + </tr> + </tbody> + </table> + <table id="table5"> + <tr><td>Row1</td></tr> + <tr><td>Row2</td></tr> + </table> + </div> +</body> +</html>
\ No newline at end of file diff --git a/accessible/tests/mochitest/jsat/test_traversal.html b/accessible/tests/mochitest/jsat/test_traversal.html new file mode 100644 index 000000000..533e9d89f --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_traversal.html @@ -0,0 +1,167 @@ +<!DOCTYPE html> +<html> +<head> + <title>Tests AccessFu TraversalRules</title> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"> + </script> + <script type="application/javascript" + src="chrome://mochikit/content/chrome-harness.js"> + </script> + + <script type="application/javascript" src="../common.js"></script> + <script type="application/javascript" src="../browser.js"></script> + <script type="application/javascript" src="../events.js"></script> + <script type="application/javascript" src="../role.js"></script> + <script type="application/javascript" src="../states.js"></script> + <script type="application/javascript" src="../pivot.js"></script> + <script type="application/javascript" src="../layout.js"></script> + + <script type="application/javascript"> + Components.utils.import("resource://gre/modules/accessibility/Traversal.jsm"); + var gBrowserWnd = null; + var gQueue = null; + + function doTest() + { + var doc = currentTabDocument(); + var docAcc = getAccessible(doc, [nsIAccessibleDocument]); + + gQueue = new eventQueue(); + + gQueue.onFinish = function onFinish() + { + closeBrowserWindow(); + } + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Heading, null, + ['heading-1', 'heading-2', 'heading-3', 'heading-5']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Entry, null, + ['input-1-1', 'label-1-2', 'input-1-3', + 'input-1-4', 'input-1-5']); + + // move back an element to hit all the form elements, because the VC is + // currently at the first input element + gQueue.push(new setVCPosInvoker(docAcc, "movePrevious", + TraversalRules.Heading, "heading-1")); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.FormElement, null, + ['input-1-1', 'label-1-2', 'button-1-1', + 'radio-1-1', 'radio-1-2', 'input-1-3', + 'input-1-4', 'button-1-2', 'checkbox-1-1', + 'select-1-1', 'select-1-2', 'checkbox-1-2', + 'select-1-3', 'input-1-5', 'button-1-3', + 'button-2-1', 'button-2-2', 'button-2-3', + 'button-2-4', 'checkbox-1-5', 'switch-1']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Button, null, + ['button-1-1', 'button-1-2', 'button-1-3', + 'button-2-1', 'button-2-2', 'button-2-3', + 'button-2-4']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.RadioButton, null, + ['radio-1-1', 'radio-1-2']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Checkbox, null, + ['checkbox-1-1', 'checkbox-1-2', 'checkbox-1-5', + 'switch-1']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Combobox, null, + ['select-1-1', 'select-1-2', 'select-1-3']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.List, null, + ['list-1', 'list-2', 'list-3']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.ListItem, null, + ['listitem-1-1', 'listitem-2-1', 'listitem-2-2', + 'listitem-3-1', 'listitem-3-2', 'listitem-3-3', + 'listitem-3-4', 'listitem-3-5', 'listitem-3-6', + 'listitem-2-3']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Graphic, null, + ['image-2', 'image-3']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Link, null, + ['link-0', 'link-1', 'link-2', 'link-3']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Anchor, null, + ['anchor-1', 'anchor-2']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Separator, null, + ['separator-1', 'separator-2']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Table, null, + ['table-1', 'grid', 'table-2']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Simple, null, + ['heading-1', 'Name:', 'input-1-1', 'label-1-2', + 'button-1-1', 'Radios are old: ', 'radio-1-1', + 'Radios are new: ', 'radio-1-2', 'Password:', + 'input-1-3', 'Unlucky number:', 'input-1-4', + 'button-1-2', 'Check me: ', 'checkbox-1-1', + 'select-1-1', 'Value 1', 'Value 2', 'Value 3', + 'Check me too: ', 'checkbox-1-2', 'But not me: ', + 'Or me! ', 'Value 1', 'Value 2', 'Value 3', + 'Electronic mailing address:', 'input-1-5', + 'button-1-3', 'heading-2', 'heading-3', + 'button-2-1', 'button-2-2', 'button-2-3', + 'button-2-4', 'Programming Language', + 'A esoteric weapon wielded by only the most ' + + 'formidable warriors, for its unrelenting strict' + + ' power is unfathomable.', + '• Lists of Programming Languages', 'Lisp ', + '1. Scheme', '2. Racket', '3. Clojure', + '4. Standard Lisp', 'link-0', ' Lisp', + 'checkbox-1-5', ' LeLisp', '• JavaScript', + 'heading-5', 'image-2', 'image-3', + 'Not actually an image', 'link-1', 'anchor-1', + 'link-2', 'anchor-2', 'link-3', '3', '1', '4', + '1', 'Sunday', 'M', 'Week 1', '3', '4', '7', '2', + '5 8', 'gridcell4', 'Just an innocuous separator', + 'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt', + 'Dirt', 'Messy Stuff', 'statusbar-1', 'statusbar-2', + 'switch-1', 'This is a MathML formula ', 'math-1', + 'with some text after.']); + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Landmark, null, + ['header-1', 'main-1', 'footer-1']); + + + queueTraversalSequence(gQueue, docAcc, TraversalRules.Control, null, + ['input-1-1', 'label-1-2', 'button-1-1', + 'radio-1-1', 'radio-1-2', 'input-1-3', + 'input-1-4', 'button-1-2', 'checkbox-1-1', + 'select-1-1', 'select-1-2', 'checkbox-1-2', + 'select-1-3', 'input-1-5', 'button-1-3', + 'button-2-1', 'button-2-2', 'button-2-3', + 'button-2-4', 'link-0', 'checkbox-1-5', + 'link-1', 'link-2', 'link-3', 'switch-1']); + + gQueue.invoke(); + } + + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function () { + /* We open a new browser because we need to test with a top-level content + document. */ + openBrowserWindow( + doTest, + getRootDirectory(window.location.href) + "doc_traversal.html"); + }); + </script> +</head> +<body id="body"> + + <a target="_blank" + title="Add tests for AccessFu TraversalRules" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=933808">Mozilla Bug 933808</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> +</body> +</html> diff --git a/accessible/tests/mochitest/jsat/test_traversal_helper.html b/accessible/tests/mochitest/jsat/test_traversal_helper.html new file mode 100644 index 000000000..f6a347ed0 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_traversal_helper.html @@ -0,0 +1,113 @@ +<!DOCTYPE html> +<html> +<head> + <title>Tests AccessFu TraversalRules</title> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"> + </script> + <script type="application/javascript" + src="chrome://mochikit/content/chrome-harness.js"> + </script> + + <script type="application/javascript" src="../common.js"></script> + <script type="application/javascript" src="../browser.js"></script> + <script type="application/javascript" src="../events.js"></script> + <script type="application/javascript" src="../role.js"></script> + <script type="application/javascript" src="../states.js"></script> + <script type="application/javascript" src="../pivot.js"></script> + <script type="application/javascript" src="../layout.js"></script> + + <script type="application/javascript"> + Components.utils.import("resource://gre/modules/accessibility/Traversal.jsm"); + + var vc; + + function accessibleIs(aAccessible, aExpected, aMessage) { + if (!aAccessible && aAccessible == aExpected) { + ok(true, "Accessible is null. " + aMessage); + } else { + ok(aAccessible.DOMNode.id == aExpected || aAccessible.name == aExpected, + "expected '" + aExpected + "', got " + prettyName(vc.position) + + ". " + aMessage); + } + } + + function walkSequence(aMethod, aRule, aExpectedSequence) { + for (var expected of aExpectedSequence) { + ok(TraversalHelper.move(vc, aMethod, aRule), + "successfully did " + aMethod + " with " + aRule); + accessibleIs(vc.position, expected, "landed on correct accessible"); + } + } + + function testTraversalHelper(aRule, aExpectedSequence) { + vc.position = null; + + walkSequence('moveNext', aRule, aExpectedSequence); + + ok(!TraversalHelper.move(vc, 'moveNext', aRule), "reached end"); + + TraversalHelper.move(vc, 'moveLast', 'Simple'); + + walkSequence('movePrevious', aRule, + Array.from(aExpectedSequence).reverse()); + + ok(!TraversalHelper.move(vc, 'movePrevious', aRule), "reached start"); + + vc.position = null; + + ok(TraversalHelper.move(vc, 'moveFirst', aRule), "moveFirst"); + + accessibleIs(vc.position, aExpectedSequence[0], + "moveFirst to correct accessible"); + + ok(TraversalHelper.move(vc, 'moveLast', aRule), "moveLast"); + + accessibleIs(vc.position, aExpectedSequence[aExpectedSequence.length - 1], + "moveLast to correct accessible"); + } + + + function doTest() + { + var doc = currentTabDocument(); + var docAcc = getAccessible(doc, [nsIAccessibleDocument]); + vc = docAcc.virtualCursor; + + testTraversalHelper('Landmark', + ['heading-1', 'heading-2', 'statusbar-1']); + + testTraversalHelper('List', + ['Programming Language', 'listitem-2-1', 'listitem-3-1']); + + testTraversalHelper('Section', + ['heading-1', 'heading-2', 'heading-3', + 'heading-5', 'link-1', 'statusbar-1']); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function () { + /* We open a new browser because we need to test with a top-level content + document. */ + openBrowserWindow( + doTest, + getRootDirectory(window.location.href) + "doc_traversal.html"); + }); + </script> +</head> +<body id="body"> + + <a target="_blank" + title="Add tests for AccessFu TraversalRules" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=xxx">Mozilla Bug xxx</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> +</body> +</html> |