Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/accessible/tests/browser/mac/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  browser_text_input.js   Sprache: JAVA

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


"use strict";

/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts(
  { name: "role.js", dir: MOCHITESTS_DIR },
  { name: "states.js", dir: MOCHITESTS_DIR }
);

function testValueChangedEventData(
  macIface,
  data,
  expectedId,
  expectedChangeValue,
  expectedEditType,
  expectedWordAtLeft
) {
  is(
    data.AXTextChangeElement.getAttributeValue("AXDOMIdentifier"),
    expectedId,
    "Correct AXTextChangeElement"
  );
  is(
    data.AXTextStateChangeType,
    AXTextStateChangeTypeEdit,
    "Correct AXTextStateChangeType"
  );

  let changeValues = data.AXTextChangeValues;
  is(changeValues.length, 1, "One element in AXTextChangeValues");
  is(
    changeValues[0].AXTextChangeValue,
    expectedChangeValue,
    "Correct AXTextChangeValue"
  );
  is(
    changeValues[0].AXTextEditType,
    expectedEditType,
    "Correct AXTextEditType"
  );

  let textMarker = changeValues[0].AXTextChangeValueStartMarker;
  ok(textMarker, "There is a AXTextChangeValueStartMarker");
  let range = macIface.getParameterizedAttributeValue(
    "AXLeftWordTextMarkerRangeForTextMarker",
    textMarker
  );
  let str = macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    range,
    "correct word before caret"
  );
  is(str, expectedWordAtLeft);
}

// Return true if the first given object a subset of the second
function isSubset(subset, superset) {
  if (typeof subset != "object" || typeof superset != "object") {
    return superset == subset;
  }

  for (let [prop, val] of Object.entries(subset)) {
    if (!isSubset(val, superset[prop])) {
      return false;
    }
  }

  return true;
}

function matchWebArea(expectedId, expectedInfo) {
  return (iface, data) => {
    if (!data) {
      return false;
    }

    let textChangeElemID =
      data.AXTextChangeElement.getAttributeValue("AXDOMIdentifier");

    return (
      iface.getAttributeValue("AXRole") == "AXWebArea" &&
      textChangeElemID == expectedId &&
      isSubset(expectedInfo, data)
    );
  };
}

function matchInput(expectedId, expectedInfo) {
  return (iface, data) => {
    if (!data) {
      return false;
    }

    return (
      iface.getAttributeValue("AXDOMIdentifier") == expectedId &&
      isSubset(expectedInfo, data)
    );
  };
}

async function synthKeyAndTestSelectionChanged(
  synthKey,
  synthEvent,
  expectedId,
  expectedSelectionString,
  expectedSelectionInfo
) {
  let selectionChangedEvents = Promise.all([
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchWebArea(expectedId, expectedSelectionInfo)
    ),
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchInput(expectedId, expectedSelectionInfo)
    ),
  ]);

  EventUtils.synthesizeKey(synthKey, synthEvent);
  let [webareaEvent, inputEvent] = await selectionChangedEvents;
  is(
    inputEvent.data.AXTextChangeElement.getAttributeValue("AXDOMIdentifier"),
    expectedId,
    "Correct AXTextChangeElement"
  );

  let rangeString = inputEvent.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    inputEvent.data.AXSelectedTextMarkerRange
  );
  is(
    rangeString,
    expectedSelectionString,
    `selection has correct value (${expectedSelectionString})`
  );

  is(
    webareaEvent.macIface.getAttributeValue("AXDOMIdentifier"),
    "body",
    "Input event target is top-level WebArea"
  );
  rangeString = webareaEvent.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    inputEvent.data.AXSelectedTextMarkerRange
  );
  is(
    rangeString,
    expectedSelectionString,
    `selection has correct value (${expectedSelectionString}) via top document`
  );

  return inputEvent;
}

function testSelectionEventLeftChar(event, expectedChar) {
  const selStart = event.macIface.getParameterizedAttributeValue(
    "AXStartTextMarkerForTextMarkerRange",
    event.data.AXSelectedTextMarkerRange
  );
  const selLeft = event.macIface.getParameterizedAttributeValue(
    "AXPreviousTextMarkerForTextMarker",
    selStart
  );
  const leftCharRange = event.macIface.getParameterizedAttributeValue(
    "AXTextMarkerRangeForUnorderedTextMarkers",
    [selLeft, selStart]
  );
  const leftCharString = event.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    leftCharRange
  );
  is(leftCharString, expectedChar, "Left character is correct");
}

function testSelectionEventLine(event, expectedLine) {
  const selStart = event.macIface.getParameterizedAttributeValue(
    "AXStartTextMarkerForTextMarkerRange",
    event.data.AXSelectedTextMarkerRange
  );
  const lineRange = event.macIface.getParameterizedAttributeValue(
    "AXLineTextMarkerRangeForTextMarker",
    selStart
  );
  const lineString = event.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    lineRange
  );
  is(lineString, expectedLine, "Line is correct");
}

async function synthKeyAndTestValueChanged(
  synthKey,
  synthEvent,
  expectedId,
  expectedTextSelectionId,
  expectedChangeValue,
  expectedEditType,
  expectedWordAtLeft
) {
  let valueChangedEvents = Promise.all([
    waitForMacEvent(
      "AXSelectedTextChanged",
      matchWebArea(expectedTextSelectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
    waitForMacEvent(
      "AXSelectedTextChanged",
      matchInput(expectedTextSelectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
    waitForMacEventWithInfo(
      "AXValueChanged",
      matchWebArea(expectedId, {
        AXTextStateChangeType: AXTextStateChangeTypeEdit,
        AXTextChangeValues: [
          {
            AXTextChangeValue: expectedChangeValue,
            AXTextEditType: expectedEditType,
          },
        ],
      })
    ),
    waitForMacEventWithInfo(
      "AXValueChanged",
      matchInput(expectedId, {
        AXTextStateChangeType: AXTextStateChangeTypeEdit,
        AXTextChangeValues: [
          {
            AXTextChangeValue: expectedChangeValue,
            AXTextEditType: expectedEditType,
          },
        ],
      })
    ),
  ]);

  EventUtils.synthesizeKey(synthKey, synthEvent);
  let [, , webareaEvent, inputEvent] = await valueChangedEvents;

  testValueChangedEventData(
    webareaEvent.macIface,
    webareaEvent.data,
    expectedId,
    expectedChangeValue,
    expectedEditType,
    expectedWordAtLeft
  );
  testValueChangedEventData(
    inputEvent.macIface,
    inputEvent.data,
    expectedId,
    expectedChangeValue,
    expectedEditType,
    expectedWordAtLeft
  );
}

async function focusIntoInput(accDoc, inputId, innerContainerId) {
  let selectionId = innerContainerId ? innerContainerId : inputId;
  let input = getNativeInterface(accDoc, inputId);
  ok(!input.getAttributeValue("AXFocused"), "input is not focused");
  ok(input.isAttributeSettable("AXFocused"), "input is focusable");
  let events = Promise.all([
    waitForMacEvent(
      "AXFocusedUIElementChanged",
      iface => iface.getAttributeValue("AXDOMIdentifier") == inputId
    ),
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchWebArea(selectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchInput(selectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
  ]);
  input.setAttributeValue("AXFocused"true);
  await events;
}

async function focusIntoInputAndType(accDoc, inputId, innerContainerId) {
  let selectionId = innerContainerId ? innerContainerId : inputId;
  await focusIntoInput(accDoc, inputId, innerContainerId);

  async function testTextInput(
    synthKey,
    expectedChangeValue,
    expectedWordAtLeft
  ) {
    await synthKeyAndTestValueChanged(
      synthKey,
      null,
      inputId,
      selectionId,
      expectedChangeValue,
      AXTextEditTypeTyping,
      expectedWordAtLeft
    );
  }

  await testTextInput("h""h""h");
  await testTextInput("e""e""he");
  await testTextInput("l""l""hel");
  await testTextInput("l""l""hell");
  await testTextInput("o""o""hello");
  await testTextInput(" "" ""hello");
  // You would expect this to be useless but this is what VO
  // consumes. I guess it concats the inserted text data to the
  // word to the left of the marker.
  await testTextInput("w""w"" ");
  await testTextInput("o""o""wo");
  await testTextInput("r""r""wor");
  await testTextInput("l""l""worl");
  await testTextInput("d""d""world");

  async function testTextDelete(expectedChangeValue, expectedWordAtLeft) {
    await synthKeyAndTestValueChanged(
      "KEY_Backspace",
      null,
      inputId,
      selectionId,
      expectedChangeValue,
      AXTextEditTypeDelete,
      expectedWordAtLeft
    );
  }

  await testTextDelete("d""worl");
  await testTextDelete("l""wor");

  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    null,
    selectionId,
    "",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    { shiftKey: true },
    selectionId,
    "o",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    { shiftKey: true },
    selectionId,
    "wo",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    null,
    selectionId,
    "",
    { AXTextStateChangeType: AXTextStateChangeTypeSelectionMove }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    { shiftKey: true, metaKey: true },
    selectionId,
    "hello ",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionBeginning,
      AXTextSelectionGranularity: AXTextSelectionGranularityLine,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    null,
    selectionId,
    "",
    { AXTextStateChangeType: AXTextStateChangeTypeSelectionMove }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowRight",
    { shiftKey: true, altKey: true },
    selectionId,
    "hello",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionNext,
      AXTextSelectionGranularity: AXTextSelectionGranularityWord,
    }
  );
}

// Test text input
addAccessibleTask(
  `<a href="#">link</a> <input id="input">`,
  async (browser, accDoc) => {
    await focusIntoInputAndType(accDoc, "input");
  },
  { topLevel: true, iframe: true, remoteIframe: true }
);

// Test content editable
addAccessibleTask(
  `<div id="input" contentEditable="true" tabindex="0" role="textbox" aria-multiline="true"><div id="inner"><br /></div></div>`,
  async (browser, accDoc) => {
    const inner = getNativeInterface(accDoc, "inner");
    const editableAncestor = inner.getAttributeValue("AXEditableAncestor");
    is(
      editableAncestor.getAttributeValue("AXDOMIdentifier"),
      "input",
      "Editable ancestor is input"
    );
    await focusIntoInputAndType(accDoc, "input");
  }
);

// Test input that gets role::EDITCOMBOBOX
addAccessibleTask(`<input type="text" id="box">`, async (browser, accDoc) => {
  const box = getNativeInterface(accDoc, "box");
  const editableAncestor = box.getAttributeValue("AXEditableAncestor");
  is(
    editableAncestor.getAttributeValue("AXDOMIdentifier"),
    "box",
    "Editable ancestor is box itself"
  );
  await focusIntoInputAndType(accDoc, "box");
});

// Test multiline caret control in a text area
addAccessibleTask(
  `<textarea id="input" cols="15">one two three four five six seven eight</textarea>`,
  async (browser, accDoc) => {
    await focusIntoInput(accDoc, "input");

    await synthKeyAndTestSelectionChanged("KEY_ArrowRight"null"input""", {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      AXTextSelectionDirection: AXTextSelectionDirectionNext,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    });

    await synthKeyAndTestSelectionChanged("KEY_ArrowDown"null"input""", {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      AXTextSelectionDirection: AXTextSelectionDirectionNext,
      AXTextSelectionGranularity: AXTextSelectionGranularityLine,
    });

    await synthKeyAndTestSelectionChanged(
      "KEY_ArrowLeft",
      { metaKey: true },
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionBeginning,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );

    await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      { metaKey: true },
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionEnd,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
  },
  { topLevel: true, iframe: true, remoteIframe: true }
);

/**
 * Test that the caret returns the correct marker when it is positioned after
 * the last character (to facilitate appending text).
 */

addAccessibleTask(
  `<input id="input" value="abc">`,
  async function (browser, docAcc) {
    await focusIntoInput(docAcc, "input");

    let event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      null,
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
      }
    );
    testSelectionEventLeftChar(event, "a");
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      null,
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
      }
    );
    testSelectionEventLeftChar(event, "b");
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      null,
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
      }
    );
    testSelectionEventLeftChar(event, "c");
  },
  { chrome: true, topLevel: true }
);

/**
 * Test that the caret returns the correct line when the caret is at the start
 * of the line.
 */

addAccessibleTask(
  `
<textarea id="hard">ab
cd
ef

gh
</textarea>
<div role="textbox" id="wrapped" contenteditable style="width: 1ch;">a b c</div>
  `,
  async function (browser, docAcc) {
    let hard = getNativeInterface(docAcc, "hard");
    await focusIntoInput(docAcc, "hard");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 0);
    let event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "cd");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 1);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "ef");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 2);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 3);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "gh");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 4);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 5);

    let wrapped = getNativeInterface(docAcc, "wrapped");
    await focusIntoInput(docAcc, "wrapped");
    is(wrapped.getAttributeValue("AXInsertionPointLineNumber"), 0);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "wrapped",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "b ");
    is(wrapped.getAttributeValue("AXInsertionPointLineNumber"), 1);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "wrapped",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "c");
    is(wrapped.getAttributeValue("AXInsertionPointLineNumber"), 2);
  },
  { chrome: true, topLevel: true }
);

Messung V0.5
C=90 H=97 G=93

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.