accessible/tests/mochitest/events/test_focus_autocomplete.xul

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 <?xml version="1.0"?>
     2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
     3 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
     4                  type="text/css"?>
     6 <!-- Firefox searchbar -->
     7 <?xml-stylesheet href="chrome://browser/content/browser.css"
     8                  type="text/css"?>
     9 <!-- SeaMonkey searchbar -->
    10 <?xml-stylesheet href="chrome://navigator/content/navigator.css"
    11                  type="text/css"?>
    13 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    14         title="Accessible focus event testing">
    16   <script type="application/javascript"
    17           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
    18   <script type="application/javascript"
    19           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
    21   <script type="application/javascript"
    22           src="../common.js" />
    23   <script type="application/javascript"
    24           src="../role.js" />
    25   <script type="application/javascript"
    26           src="../states.js" />
    27   <script type="application/javascript"
    28           src="../events.js" />
    30   <script type="application/javascript"
    31           src="../autocomplete.js" />
    33   <script type="application/javascript">
    34   <![CDATA[
    35     ////////////////////////////////////////////////////////////////////////////
    36     // Hacky stuffs
    38     // This is the hack needed for searchbar work outside of browser.
    39     function getBrowser()
    40     {
    41       return {
    42         mCurrentBrowser: { engines: new Array() }
    43       };
    44     }
    46     ////////////////////////////////////////////////////////////////////////////
    47     // Invokers
    49     function loadFormAutoComplete(aIFrameID)
    50     {
    51       this.iframeNode = getNode(aIFrameID);
    52       this.iframe = getAccessible(aIFrameID);
    54       this.eventSeq = [
    55         new invokerChecker(EVENT_REORDER, this.iframe)
    56       ];
    58       this.invoke = function loadFormAutoComplete_invoke()
    59       {
    60         var url = "data:text/html,<html><body><form id='form'>" +
    61           "<input id='input' name='a11ytest-formautocomplete'>" +
    62           "</form></body></html>";
    63         this.iframeNode.setAttribute("src", url);
    64       }
    66       this.getID = function loadFormAutoComplete_getID()
    67       {
    68         return "load form autocomplete page";
    69       }
    70     }
    72     function initFormAutoCompleteBy(aIFrameID, aAutoCompleteValue)
    73     {
    74       this.iframe = getAccessible(aIFrameID);
    76       this.eventSeq = [
    77         new invokerChecker(EVENT_REORDER, this.iframe)
    78       ];
    80       this.invoke = function initFormAutoCompleteBy_invoke()
    81       {
    82         var iframeDOMDoc = getIFrameDOMDoc(aIFrameID);
    84         var inputNode = iframeDOMDoc.getElementById("input");
    85         inputNode.value = aAutoCompleteValue;
    86         var formNode = iframeDOMDoc.getElementById("form");
    87         formNode.submit();
    88       }
    90       this.getID = function initFormAutoCompleteBy_getID()
    91       {
    92         return "init form autocomplete by '" + aAutoCompleteValue + "'";
    93       }
    94     }
    96     function loadHTML5ListAutoComplete(aIFrameID)
    97     {
    98       this.iframeNode = getNode(aIFrameID);
    99       this.iframe = getAccessible(aIFrameID);
   101       this.eventSeq = [
   102         new invokerChecker(EVENT_REORDER, this.iframe)
   103       ];
   105       this.invoke = function loadHTML5ListAutoComplete_invoke()
   106       {
   107         var url = "data:text/html,<html><body>" +
   108           "<datalist id='cities'><option>hello</option><option>hi</option></datalist>" +
   109           "<input id='input' list='cities'>" +
   110           "</body></html>";
   111         this.iframeNode.setAttribute("src", url);
   112       }
   114       this.getID = function loadHTML5ListAutoComplete_getID()
   115       {
   116         return "load HTML5 list autocomplete page";
   117       }
   118     }
   120     function removeChar(aID, aCheckerOrEventSeq)
   121     {
   122       this.__proto__ = new synthAction(aID, aCheckerOrEventSeq);
   124       this.invoke = function removeChar_invoke()
   125       {
   126         synthesizeKey("VK_LEFT", { shiftKey: true });
   127         synthesizeKey("VK_DELETE", {});
   128       }
   130       this.getID = function removeChar_getID()
   131       {
   132         return "remove char on " + prettyName(aID);
   133       }
   134     }
   136     function replaceOnChar(aID, aChar, aCheckerOrEventSeq)
   137     {
   138       this.__proto__ = new synthAction(aID, aCheckerOrEventSeq);
   140       this.invoke = function replaceOnChar_invoke()
   141       {
   142         this.DOMNode.select();
   143         synthesizeKey(aChar, {});
   144       }
   146       this.getID = function replaceOnChar_getID()
   147       {
   148         return "replace on char '" + aChar + "' for" + prettyName(aID);
   149       }
   150     }
   152     function focusOnMouseOver(aIDFunc, aIDFuncArg)
   153     {
   154       this.eventSeq = [ new focusChecker(aIDFunc, aIDFuncArg) ];
   156       this.invoke = function focusOnMouseOver_invoke()
   157       {
   158         this.id = aIDFunc.call(null, aIDFuncArg);
   159         this.node = getNode(this.id);
   160         this.window = this.node.ownerDocument.defaultView;
   162         if (this.node.localName == "tree") {
   163           var tree = getAccessible(this.node);
   164           var accessible = getAccessible(this.id);
   165           if (tree != accessible) {
   166             var itemX = {}, itemY = {}, treeX = {}, treeY = {};
   167             accessible.getBounds(itemX, itemY, {}, {});
   168             tree.getBounds(treeX, treeY, {}, {});
   169             this.x = itemX.value - treeX.value;
   170             this.y = itemY.value - treeY.value;
   171           }
   172         }
   174         // Generate mouse move events in timeouts until autocomplete popup list
   175         // doesn't have it, the reason is do that because autocomplete popup
   176         // ignores mousemove events firing in too short range.
   177         synthesizeMouse(this.node, this.x, this.y, { type: "mousemove" });
   178         this.doMouseMoveFlood(this);
   179       }
   181       this.finalCheck = function focusOnMouseOver_getID()
   182       {
   183         this.isFlooding = false;
   184       }
   186       this.getID = function focusOnMouseOver_getID()
   187       {
   188         return "mouse over on " + prettyName(aIDFunc.call(null, aIDFuncArg));
   189       }
   191       this.doMouseMoveFlood = function focusOnMouseOver_doMouseMoveFlood(aThis)
   192       {
   193         synthesizeMouse(aThis.node, aThis.x + 1, aThis.y + 1,
   194                         { type: "mousemove" }, aThis.window);
   196         if (aThis.isFlooding)
   197           aThis.window.setTimeout(aThis.doMouseMoveFlood, 0, aThis);
   198       }
   200       this.id = null;
   201       this.node = null;
   202       this.window = null;
   204       this.isFlooding = true;
   205       this.x = 1;
   206       this.y = 1;
   207     }
   209     function selectByClick(aIDFunc, aIDFuncArg,
   210                            aFocusTargetFunc, aFocusTargetFuncArg)
   211     {
   212       this.eventSeq = [ new focusChecker(aFocusTargetFunc, aFocusTargetFuncArg) ];
   214       this.invoke = function selectByClick_invoke()
   215       {
   216         var id = aIDFunc.call(null, aIDFuncArg);
   217         var node = getNode(id);
   218         var targetWindow = node.ownerDocument.defaultView;
   220         var x = 0, y = 0;
   221         if (node.localName == "tree") {
   222           var tree = getAccessible(node);
   223           var accessible = getAccessible(id);
   224           if (tree != accessible) {
   225             var itemX = {}, itemY = {}, treeX = {}, treeY = {};
   226             accessible.getBounds(itemX, itemY, {}, {});
   227             tree.getBounds(treeX, treeY, {}, {});
   228             x = itemX.value - treeX.value;
   229             y = itemY.value - treeY.value;
   230           }
   231         }
   233         synthesizeMouseAtCenter(node, {}, targetWindow);
   234       }
   236       this.getID = function selectByClick_getID()
   237       {
   238         return "select by click " + prettyName(aIDFunc.call(null, aIDFuncArg));
   239       }
   240     }
   242     ////////////////////////////////////////////////////////////////////////////
   243     // Target getters
   245     function getItem(aItemObj)
   246     {
   247       var autocomplete = aItemObj.autocomplete;
   248       var autocompleteNode = aItemObj.autocompleteNode;
   250       // XUL searchbar
   251       if (autocompleteNode.localName == "searchbar") {
   252         var popupNode = autocompleteNode._popup;
   253         if (popupNode) {
   254           var list = getAccessible(popupNode);
   255           return list.getChildAt(aItemObj.index);
   256         }
   257       }
   259       // XUL autocomplete
   260       var popupNode = autocompleteNode.popup;
   261       if (!popupNode) {
   262         // HTML form autocomplete
   263         var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
   264           getService(Components.interfaces.nsIAutoCompleteController);
   265         popupNode = controller.input.popup.QueryInterface(nsIDOMNode);
   266       }
   268       if (popupNode) {
   269         if ("richlistbox" in popupNode) {
   270           var list = getAccessible(popupNode.richlistbox);
   271           return list.getChildAt(aItemObj.index);
   272         }
   274         var list = getAccessible(popupNode.tree);
   275         return list.getChildAt(aItemObj.index + 1);
   276       }
   277     }
   279     function getTextEntry(aID)
   280     {
   281       // For form autocompletes the autocomplete widget and text entry widget
   282       // is the same widget, for XUL autocompletes the text entry is a first
   283       // child.
   284       var localName = getNode(aID).localName;
   286       // XUL autocomplete
   287       if (localName == "textbox")
   288         return getAccessible(aID).firstChild;
   290       // HTML form autocomplete
   291       if (localName == "input")
   292         return getAccessible(aID);
   294       // XUL searchbar
   295       if (localName == "searchbar")
   296         return getAccessible(getNode(aID).textbox.inputField);
   298       return null;
   299     }
   301     function itemObj(aID, aIdx)
   302     {
   303       this.autocompleteNode = getNode(aID);
   305       this.autocomplete = this.autocompleteNode.localName == "searchbar" ?
   306         getAccessible(this.autocompleteNode.textbox) :
   307         getAccessible(this.autocompleteNode);
   309       this.index = aIdx;
   310     }
   312     function getIFrameDOMDoc(aIFrameID)
   313     {
   314       return getNode(aIFrameID).contentDocument;
   315     }
   317     ////////////////////////////////////////////////////////////////////////////
   318     // Test helpers
   320     function queueAutoCompleteTests(aID)
   321     {
   322       // focus autocomplete text entry
   323       gQueue.push(new synthFocus(aID, new focusChecker(getTextEntry, aID)));
   325       // open autocomplete popup
   326       gQueue.push(new synthDownKey(aID, new nofocusChecker()));
   328       // select second option ('hi' option), focus on it
   329       gQueue.push(new synthUpKey(aID,
   330                                  new focusChecker(getItem, new itemObj(aID, 1))));
   332       // choose selected option, focus on text entry
   333       gQueue.push(new synthEnterKey(aID, new focusChecker(getTextEntry, aID)));
   335       // remove char, autocomplete popup appears
   336       gQueue.push(new removeChar(aID, new nofocusChecker()));
   338       // select first option ('hello' option), focus on it
   339       gQueue.push(new synthDownKey(aID,
   340                                    new focusChecker(getItem, new itemObj(aID, 0))));
   342       // mouse move on second option ('hi' option), focus on it
   343       gQueue.push(new focusOnMouseOver(getItem, new itemObj(aID, 1)));
   345       // autocomplete popup updated (no selected item), focus on textentry
   346       gQueue.push(new synthKey(aID, "e", null, new focusChecker(getTextEntry, aID)));
   348       // select first option ('hello' option), focus on it
   349       gQueue.push(new synthDownKey(aID,
   350                                    new focusChecker(getItem, new itemObj(aID, 0))));
   352       // popup gets hidden, focus on textentry
   353       gQueue.push(new synthRightKey(aID, new focusChecker(getTextEntry, aID)));
   355       // popup gets open, no focus
   356       gQueue.push(new synthOpenComboboxKey(aID, new nofocusChecker()));
   358       // select first option again ('hello' option), focus on it
   359       gQueue.push(new synthDownKey(aID,
   360                                    new focusChecker(getItem, new itemObj(aID, 0))));
   362       // no option is selected, focus on text entry
   363       gQueue.push(new synthUpKey(aID, new focusChecker(getTextEntry, aID)));
   365       // close popup, no focus
   366       gQueue.push(new synthEscapeKey(aID, new nofocusChecker()));
   368       // autocomplete popup appears (no selected item), focus stays on textentry
   369       gQueue.push(new replaceOnChar(aID, "h", new nofocusChecker()));
   371       // mouse move on first option ('hello' option), focus on it
   372       gQueue.push(new focusOnMouseOver(getItem, new itemObj(aID, 0)));
   374       // click first option ('hello' option), popup closes, focus on text entry
   375       gQueue.push(new selectByClick(getItem, new itemObj(aID, 0), getTextEntry, aID));
   376     }
   378     ////////////////////////////////////////////////////////////////////////////
   379     // Tests
   381     //gA11yEventDumpID = "eventdump"; // debug stuff
   382     //gA11yEventDumpToConsole = true; // debug stuff
   384     var gInitQueue = null;
   385     function initTests()
   386     {
   387       if (SEAMONKEY || MAC) {
   388         todo(false, "Skipping this test on SeaMonkey ftb. (Bug 718237), and on Mac (bug 746177)");
   389         shutdownAutoComplete();
   390         SimpleTest.finish();
   391         return;
   392       }
   394       gInitQueue = new eventQueue();
   395       gInitQueue.push(new loadFormAutoComplete("iframe"));
   396       gInitQueue.push(new initFormAutoCompleteBy("iframe", "hello"));
   397       gInitQueue.push(new initFormAutoCompleteBy("iframe", "hi"));
   398       gInitQueue.push(new loadHTML5ListAutoComplete("iframe2"));
   399       gInitQueue.onFinish = function initQueue_onFinish()
   400       {
   401         SimpleTest.executeSoon(doTests);
   402         return DO_NOT_FINISH_TEST;
   403       }
   404       gInitQueue.invoke();
   405     }
   407     var gQueue = null;
   408     function doTests()
   409     {
   410       // Test focus events.
   411       gQueue = new eventQueue();
   413       ////////////////////////////////////////////////////////////////////////////
   414       // tree popup autocomplete tests
   415       queueAutoCompleteTests("autocomplete");
   417       ////////////////////////////////////////////////////////////////////////////
   418       // richlistbox popup autocomplete tests
   419       queueAutoCompleteTests("richautocomplete");
   421       ////////////////////////////////////////////////////////////////////////////
   422       // HTML form autocomplete tests
   423       queueAutoCompleteTests(getIFrameDOMDoc("iframe").getElementById("input"));
   425       ////////////////////////////////////////////////////////////////////////////
   426       // HTML5 list autocomplete tests
   427       queueAutoCompleteTests(getIFrameDOMDoc("iframe2").getElementById("input"));
   429       ////////////////////////////////////////////////////////////////////////////
   430       // searchbar tests
   432       // focus searchbar, focus on text entry
   433       gQueue.push(new synthFocus("searchbar",
   434                                  new focusChecker(getTextEntry, "searchbar")));
   435       // open search engine popup, no focus
   436       gQueue.push(new synthOpenComboboxKey("searchbar", new nofocusChecker()));
   437       // select first item, focus on it
   438       gQueue.push(new synthDownKey("searchbar",
   439                                    new focusChecker(getItem, new itemObj("searchbar", 0))));
   440       // mouse over on second item, focus on it
   441       gQueue.push(new focusOnMouseOver(getItem, new itemObj("searchbar", 1)));
   442       // press enter key, focus on text entry
   443       gQueue.push(new synthEnterKey("searchbar",
   444                                     new focusChecker(getTextEntry, "searchbar")));
   445       // click on search button, open popup, focus goes to document
   446       var searchBtn = getAccessible(getNode("searchbar").searchButton);
   447       gQueue.push(new synthClick(searchBtn, new focusChecker(document)));
   448       // select first item, focus on it
   449       gQueue.push(new synthDownKey("searchbar",
   450                                    new focusChecker(getItem, new itemObj("searchbar", 0))));
   451       // close popup, focus goes on document
   452       gQueue.push(new synthEscapeKey("searchbar", new focusChecker(document)));
   454       gQueue.onFinish = function()
   455       {
   456         // unregister 'test-a11y-search' autocomplete search
   457         shutdownAutoComplete();
   458       }
   459       gQueue.invoke(); // Will call SimpleTest.finish();
   460     }
   462     SimpleTest.waitForExplicitFinish();
   464     // Register 'test-a11y-search' autocomplete search.
   465     // XPFE AutoComplete needs to register early.
   466     initAutoComplete([ "hello", "hi" ],
   467                      [ "Beep beep'm beep beep yeah", "Baby you can drive my car" ]);
   469     addA11yLoadEvent(initTests);
   470   ]]>
   471   </script>
   473   <hbox flex="1" style="overflow: auto;">
   474     <body xmlns="http://www.w3.org/1999/xhtml">
   475       <a target="_blank"
   476          href="https://bugzilla.mozilla.org/show_bug.cgi?id=383759"
   477          title="Focus event inconsistent for search box autocomplete">
   478         Mozilla Bug 383759
   479       </a>
   480       <a target="_blank"
   481          href="https://bugzilla.mozilla.org/show_bug.cgi?id=673958"
   482          title="Rework accessible focus handling">
   483         Mozilla Bug 673958
   484       </a>
   485       <a target="_blank"
   486          href="https://bugzilla.mozilla.org/show_bug.cgi?id=559766"
   487          title="Add accessibility support for @list on HTML input and for HTML datalist">
   488         Mozilla Bug 559766
   489       </a>
   490       <p id="display"></p>
   491       <div id="content" style="display: none"></div>
   492       <pre id="test">
   493       </pre>
   494     </body>
   496     <vbox flex="1">
   497       <textbox id="autocomplete" type="autocomplete"
   498                autocompletesearch="test-a11y-search"/>
   500       <textbox id="richautocomplete" type="autocomplete"
   501                autocompletesearch="test-a11y-search"
   502                autocompletepopup="richpopup"/>
   503       <panel id="richpopup" type="autocomplete-richlistbox" noautofocus="true"/>
   505       <iframe id="iframe"/>
   507       <iframe id="iframe2"/>
   509       <searchbar id="searchbar"/>
   511       <vbox id="eventdump"/>
   512     </vbox>
   513   </hbox>
   514 </window>

mercurial