accessible/tests/mochitest/test_nsIAccessibleHyperLink.html
author Jason Evans <jasone@canonware.com>
Fri, 20 Jun 2008 10:29:43 -0700
changeset 15456 38972d94e6312cca26dc09bb1d8ac4a9bec84b1c
parent 15454 f0a83903e4bff3b7238a57cd71a3d177e2579028
child 21256 ed2e583d9edfdc6844869bb96f3bd0d636f3f3b2
permissions -rw-r--r--
Bug 431743: Upstream jemalloc fixes, r=benjamin Incorporate upstream jemalloc fixes from FreeBSD: * Detect overflow for huge allocations via sbrk(2). * Fix deadlock for base (internal) allocations in OOM case. * Fix bitmap vector initialization for small allocation runs.

<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=418368
-->
<head>
  <title>nsIHyperLinkAccessible chrome tests</title>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />

  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>

  <script type="application/javascript">
    var gAccRetrieval = null;

    function testThis(aID, aAcc, aRole, aAnchors, aName, aValid, aStartIndex,
                      aEndIndex)
    {
      is(aAcc.finalRole, aRole, "Wrong role for ID " + aID + "!");
      is(aAcc.anchorCount, aAnchors, "Wrong number of anchors for ID "
                                      + aID + "!");
      is(aAcc.getAnchor(0).name, aName, "Wrong name for ID "
                                        + aID + "!");
      is(aAcc.valid, aValid, "No correct valid state for ID "
                             + aID + "!");
      is(aAcc.startIndex, aStartIndex, "Wrong startIndex value for ID "
                                       + aID + "!");
      is(aAcc.endIndex, aEndIndex, "Wrong endIndex value for ID "
                                   + aID + "!");
    }

    function testFocus(aID, aAcc, aSelectedBefore, aSelectedAfter)
    {
      is(aAcc.selected, aSelectedBefore,
         "Wrong selected state before focus for ID " + aID + "!");
      document.getElementById(aID).focus();
      is(aAcc.selected, aSelectedAfter,
         "Wrong seleccted state after focus for ID " + aID + "!");
    }

    function testStates(aID, aAcc, aState, aExtraState, aAbsentState,
                        aShowStateDebugFlag)
    {
      var state = {}, extraState = {};
      aAcc.getFinalState(state, extraState);

      if (aShowStateDebugFlag) {
        var list = gAccRetrieval.getStringStates(state.value, 0);

        var str = "";
        for (var i = 0; i < list.length; i++)
          str += list.item(i) + "\n";

        alert(str);
      }

      is(state.value & aState, aState, "Wrong state bits for ID " + aID + "!");
      is(extraState.value & aExtraState, aExtraState, 
         "Wrong extra state bits for ID " + aID + "!");
      if (aAbsentState != 0)
        is(state.value & aAbsentState, 0, "state bits should not be present in ID "
           + aID + "!");
    }

    function testAction(aId, aAcc, aActionName)
    {
      var numActions = aActionName ? 1 : 0;
      is(aAcc.numActions, numActions,
         "Wrong actions number for ID " + aId);
      try {
        is(aAcc.getActionName(0), aActionName,
           "Wrong action name for ID " + aId);
      } catch (e) {
        if (numActions)
          ok(false, "Exception on action name getting for ID " + aId);
        else
          ok(true, "Correct action name for ID " + aId);
      }
    }

    function doTest()
    {
      // Mapping needed state flags for easier handling.
      const state_focusable = 
            Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
      const state_focused = 
            Components.interfaces.nsIAccessibleStates.STATE_FOCUSED;
      const state_selectable = 
            Components.interfaces.nsIAccessibleStates.STATE_SELECTABLE;
      const state_linked = 
            Components.interfaces.nsIAccessibleStates.STATE_LINKED;
      const state_traversed = 
            Components.interfaces.nsIAccessibleStates.STATE_TRAVERSED;

      const ext_state_multi_line = 
            Components.interfaces.nsIAccessibleStates.EXT_STATE_MULTI_LINE;
      const ext_state_horizontal = 
            Components.interfaces.nsIAccessibleStates.EXT_STATE_HORIZONTAL;
      const ext_state_required = 
            Components.interfaces.nsIAccessibleStates.STATE_REQUIRED;
      const ext_state_invalid = 
            Components.interfaces.nsIAccessibleStates.STATE_INVALID;

      gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
                      getService(Components.interfaces.nsIAccessibleRetrieval);

      //////////////////////////////////////////////////////////////////////////
      // normal hyperlink
      var normalHyperlinkElement = document.getElementById("NormalHyperlink");
      var normalHyperlinkAcc;
      try {
        normalHyperlinkAcc = gAccRetrieval.getAccessibleFor(normalHyperlinkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(normalHyperlinkAcc, "no interface for normal hyperlink!");
      }
      testThis("NormalHyperlink", normalHyperlinkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "Mozilla Foundation", true, 18, 19);
      is(normalHyperlinkAcc.getURI(0).spec, "http://www.mozilla.org/", 
         "URI wrong for normalHyperlinkElement!");
      testStates("NormalHyperlink", normalHyperlinkAcc,
                 (state_focusable | state_linked),
                 (ext_state_horizontal), (0));
      testFocus("NormalHyperlink", normalHyperlinkAcc, false, true);
      testStates("NormalHyperlink", normalHyperlinkAcc,
                 (state_focusable | state_focused | state_linked),
                 (ext_state_horizontal), (0));

      //////////////////////////////////////////////////////////////////////////
      // ARIA hyperlink
      var ariaHyperlinkElement = document.getElementById("AriaHyperlink");
      var ariaHyperlinkAcc;
      try {
        ariaHyperlinkAcc = gAccRetrieval.getAccessibleFor(ariaHyperlinkElement).
            QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(ariaHyperlinkAcc, "no interface for ARIA Hyperlink!");
      }
      testThis("AriaHyperlink", ariaHyperlinkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
               "Mozilla Foundation Home", true, 32, 33);
      testStates("AriaHyperlink", ariaHyperlinkAcc,
                 (state_focusable | state_linked),
                 (ext_state_horizontal), (0));
      testFocus("AriaHyperlink", ariaHyperlinkAcc, false, true);
      testStates("AriaHyperlink", ariaHyperlinkAcc,
                 (state_focusable | state_focused | state_linked),
                 (ext_state_horizontal), (0));
      testAction("AriaHyperlink", ariaHyperlinkAcc, "click");

      //////////////////////////////////////////////////////////////////////////
      // ARIA hyperlink with status invalid
      var invalidAriaHyperlinkElement =
          document.getElementById("InvalidAriaHyperlink");
      var invalidAriaHyperlinkAcc;
      try {
        invalidAriaHyperlinkAcc =
               gAccRetrieval.getAccessibleFor(invalidAriaHyperlinkElement).
               QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(invalidAriaHyperlinkAcc, "no interface for invalid ARIA hyperlink!");
      }
      is(invalidAriaHyperlinkAcc.valid, false, "Should not be valid!");
      testStates("InvalidAriaHyperlink", invalidAriaHyperlinkAcc,
                 (state_linked),
                 (ext_state_horizontal), (state_focusable));
      testFocus("InvalidAriaHyperlink", invalidAriaHyperlinkAcc,
                false, false);

      //////////////////////////////////////////////////////////////////////////
      // image map and its link children
      var imageMapHyperlinkElement =
          document.getElementById("imgmap");
      var imageMapHyperlinkAcc;
      try {
        imageMapHyperlinkAcc =
             gAccRetrieval.getAccessibleFor(imageMapHyperlinkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(imageMapHyperlinkAcc, "no Image Map interface!");
      }
      testThis("imgmap", imageMapHyperlinkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_IMAGE_MAP, 2, 
               "b", true, 83, 84);
      is(imageMapHyperlinkAcc.getURI(0).spec,
         "http://www.bbc.co.uk/radio4/atoz/index.shtml#b", "URI wrong!");
      is(imageMapHyperlinkAcc.getURI(1).spec,
         "http://www.bbc.co.uk/radio4/atoz/index.shtml#a", "URI wrong!");
      testStates("imgmap", imageMapHyperlinkAcc,
                 (0),
                 (ext_state_horizontal), (0));

      var area1 = imageMapHyperlinkAcc.firstChild;
      ok(area1, "no children in image map acc!");
      var area1HL;
      try {
        area1HL =
             area1.QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch (e) {
        ok(area1HL, "no interface for first child of Image Map!");
      }
      testThis("Area1", area1HL,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
               "b", true, 0, 1);
      is(area1HL.getURI(0).spec,
         "http://www.bbc.co.uk/radio4/atoz/index.shtml#b", "URI wrong!");
      testStates("Area1", area1HL,
                 (state_linked),
                 (0), (0));

      var area2 = area1.nextSibling;
      ok(area2, "no next sibling!");
      var area2HL;
      try {
        area2HL =
             area2.QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch (e) {
        ok(area2HL, "no interface for second child of Image Map!");
      }
      testThis("Area2", area2HL,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
               "a", true, 1, 2);
      is(area2HL.getURI(0).spec,
         "http://www.bbc.co.uk/radio4/atoz/index.shtml#a", "URI wrong!");
      testStates("Area2", area2HL,
                 (state_linked),
                 (0), (0));

      //////////////////////////////////////////////////////////////////////////
      // empty hyperlink
      var emptyLinkElement = document.getElementById("emptyLink");
      var EmptyHLAcc;
      try {
        EmptyHLAcc =
             gAccRetrieval.getAccessibleFor(emptyLinkElement).
             QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch (e) {
        ok(EmptyHLAcc, "no interface for empty link!");
      }
      testThis("emptyLink", EmptyHLAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
               null, true, 98, 99);
      testStates("emptyLink", EmptyHLAcc,
                 (state_focusable | state_linked),
                 (ext_state_horizontal), (0));
      testAction("emptyLink", EmptyHLAcc, "jump");

      //////////////////////////////////////////////////////////////////////////
      // normal hyperlink with embedded span
      var hyperlinkElementWithSpan = document.getElementById("LinkWithSpan");
      var hyperlinkWithSpanAcc;
      try {
        hyperlinkWithSpanAcc =
              gAccRetrieval.getAccessibleFor(hyperlinkElementWithSpan).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(hyperlinkWithSpanAcc, "no interface for hyperlink with span!");
      }
      testThis("LinkWithSpan", hyperlinkWithSpanAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "Heise Online", true, 124, 125);
      is(hyperlinkWithSpanAcc.getURI(0).spec, "http://www.heise.de/", 
         "URI wrong for hyperlinkElementWithSpan!");
      testStates("LinkWithSpan", hyperlinkWithSpanAcc,
                 (state_focusable | state_linked),
                 (ext_state_horizontal), (0));
      testFocus("LinkWithSpan", hyperlinkWithSpanAcc, false, true);
      testStates("LinkWithSpan", hyperlinkWithSpanAcc,
                 (state_focusable | state_focused | state_linked),
                 (ext_state_horizontal), (0));
      testAction("LinkWithSpan", hyperlinkWithSpanAcc, "jump");

      //////////////////////////////////////////////////////////////////////////
      // Named anchor, should never have state_linked
      var namedAnchorElement = document.getElementById("namedAnchor");
      var namedAnchorAcc;
      try {
        namedAnchorAcc = gAccRetrieval.getAccessibleFor(namedAnchorElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(namedAnchorAcc, "no interface for named anchor!");
      }
      testThis("namedAnchor", namedAnchorAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "This should never be of state_linked", true, 202, 203);
      testStates("namedAnchor", namedAnchorAcc,
                 (state_selectable),
                 (ext_state_horizontal), (state_focusable | state_linked));
      testAction("namedAnchor", namedAnchorAcc, "");

      //////////////////////////////////////////////////////////////////////////
      // No link (hasn't any attribute), should never have state_linked
      var noLinkElement = document.getElementById("noLink");
      var noLinkAcc;
      try {
        noLinkAcc = gAccRetrieval.getAccessibleFor(noLinkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(noLinkAcc, "no interface for named anchor!");
      }
      testThis("noLink", noLinkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "This should never be of state_linked", true, 262, 263);
      testStates("noLink", noLinkAcc,
                 0,
                 (ext_state_horizontal), (state_focusable | state_linked));
      testAction("noLink", noLinkAcc, "");

      //////////////////////////////////////////////////////////////////////////
      // Link with registered 'click' event, should have state_linked
      var linkWithClickElement = document.getElementById("linkWithClick");
      var linkWithClickAcc;
      try {
        linkWithClickAcc = gAccRetrieval.getAccessibleFor(linkWithClickElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(linkWithClickAcc, "no interface for named anchor!");
      }
      testThis("linkWithClick", linkWithClickAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "This should have state_linked", true, 301, 302);
      testStates("linkWithClick", linkWithClickAcc,
                 (state_linked),
                 (ext_state_horizontal), 0);
      testAction("linkWithClick", linkWithClickAcc, "click");

      //////////////////////////////////////////////////////////////////////////
      // Maps to group links (bug 431615).
      var linksMapElement = document.getElementById("linksmap");
      var linksMapAcc;
      try {
        linksMapAcc = gAccRetrieval.getAccessibleFor(linksMapElement);
      } catch(e) { }

      ok(linksMapAcc, "no accessible for map grouping links!");

      //////////////////////////////////////////////////////////////////////////
      // Link with title attribute, no name from the subtree (bug 438325).
      var id = "linkWithTitleNoNameFromSubtree";
      var linkElement = document.getElementById(id);
      var linkAcc;
      try {
        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(linkAcc, "no interface for link with ID " + id + "!");
      }
      testThis(id, linkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "Link with title", true, 354, 355);
      testStates(id, linkAcc,
                 (state_linked),
                 (ext_state_horizontal), 0);
      testAction(id, linkAcc, "jump");

      //////////////////////////////////////////////////////////////////////////
      // Link with title attribute, name from the subtree - onsreen name
      // (bug 438325).
      id = "linkWithTitleNameFromSubtree";
      linkElement = document.getElementById(id);
      linkAcc;
      try {
        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(linkAcc, "no interface for link with ID " + id + "!");
      }
      testThis(id, linkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "the name from subtree", true, 403, 404);
      testStates(id, linkAcc,
                 (state_linked),
                 (ext_state_horizontal), 0);
      testAction(id, linkAcc, "jump");

      //////////////////////////////////////////////////////////////////////////
      // Link with title attribute, name from the nested html:img (bug 438325).
      id = "linkWithTitleNameFromImg";
      linkElement = document.getElementById(id);
      linkAcc;
      try {
        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(linkAcc, "no interface for link with ID " + id + "!");
      }
      testThis(id, linkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "The title for link", true, 458, 459);
      testStates(id, linkAcc,
                 (state_linked),
                 (ext_state_horizontal), 0);
      testAction(id, linkAcc, "jump");

      //////////////////////////////////////////////////////////////////////////
      // Link with label, no name from the subtree (bug 438325).
      id = "linkWithLabelNoNameFromSubtree";
      linkElement = document.getElementById(id);
      linkAcc;
      try {
        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
      } catch(e) {
        ok(linkAcc, "no interface for link with ID " + id + "!");
      }
      testThis(id, linkAcc,
               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
               "Link with label and nested image:", true, 462, 463);
      testStates(id, linkAcc,
                 (state_linked),
                 (ext_state_horizontal), 0);
      testAction(id, linkAcc, "jump");

      //////////////////////////////////////////////////////////////////////////
      //
      SimpleTest.finish();
    }

    SimpleTest.waitForExplicitFinish();
    addLoadEvent(doTest);
  </script>
</head>
<body>

  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418368">Mozilla Bug 418368</a>
  <p id="display"></p>
  <div id="content" style="display: none"></div>
  <pre id="test">
  </pre>

  <br>Simple link:<br>
  <a id="NormalHyperlink" href="http://www.mozilla.org">Mozilla Foundation</a>
  <br>ARIA link:<br>
  <span id="AriaHyperlink" role="link"
         onclick="window.open('http://www.mozilla.org/');"
         tabindex="0">Mozilla Foundation Home</span>
  <br>Invalid, non-focusable hyperlink:<br>
  <span id="InvalidAriaHyperlink" role="link" aria-invalid="true"
        onclick="window.open('http:/www.mozilla.org/');">Invalid link</span>
  <br>Image map:<br>
  <map name="atoz_map">
    <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
          coords="17,0,30,14"
          alt="b"
          shape="rect"></area>
    <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
          coords="0,0,13,14"
          alt="a"
          shape="rect"></area>
  </map>
  <img width="447" id="imgmap"
       height="15"
       usemap="#atoz_map"
       src="http://www.bbc.co.uk/radio4/images/letters.gif"></img>

  <br>Empty link:<br>
  <a id="emptyLink" href=""><img src=""></img></a>

  <br>Link with embedded span<br>
  <a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a>

  <br>Named anchor, must not have "linked" state for it to be exposed correctly:<br>
  <a id="namedAnchor" name="named_anchor">This should never be of state_linked</a>

  <br>Link having no attributes, must not have "linked" state:</br>
  <a id="noLink">This should never be of state_linked</a>

  <br>Link with registered 'click' event: </br>
  <a id="linkWithClick" onclick="var clicked = true;">This should have state_linked</a>

  <br>Link with title attribute (no name from subtree): </br>
  <a id="linkWithTitleNoNameFromSubtree" href="http://www.heise.de/"
     title="Link with title"><img src=""/></a>

  <br>Link with title attribute (name from subtree): </br>
  <a id="linkWithTitleNameFromSubtree" href="http://www.heise.de/"
     title="Link with title">the name from subtree</a>

  <br>Link with title attribute (name from nested image): </br>
  <a id="linkWithTitleNameFromImg" href="http://www.heise.de/"
     title="Link with title"><img src="" alt="The title for link"/></a>

  <br><label for="linkWithLabelNoNameFromSubtree">Link with label and nested image: </label></br>
  <a id="linkWithLabelNoNameFromSubtree"
     href="http://www.heise.de/"><img src=""/></a>

  <br>Map that is used to group links (www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass),
   also see the bug 431615:<br>
  <map id="linksmap" title="Site navigation">
    <ul>
      <li><a href="http://mozilla.org">About the project</a></li>
      <li><a href="http://mozilla.org">Sites and sounds</a></li>
    </ul>
  </map>

</body>
</html>