summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/chrome/file_editor_with_autocomplete.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/chrome/file_editor_with_autocomplete.js')
-rw-r--r--toolkit/content/tests/chrome/file_editor_with_autocomplete.js627
1 files changed, 627 insertions, 0 deletions
diff --git a/toolkit/content/tests/chrome/file_editor_with_autocomplete.js b/toolkit/content/tests/chrome/file_editor_with_autocomplete.js
new file mode 100644
index 0000000000..78611efc70
--- /dev/null
+++ b/toolkit/content/tests/chrome/file_editor_with_autocomplete.js
@@ -0,0 +1,627 @@
+// nsDoTestsForEditorWithAutoComplete tests basic functions of editor with autocomplete.
+// Users must include SimpleTest.js and EventUtils.js, and register "Mozilla" to the autocomplete for the target.
+
+async function waitForCondition(condition) {
+ return new Promise(resolve => {
+ var tries = 0;
+ var interval = setInterval(function () {
+ if (condition() || tries >= 60) {
+ moveOn();
+ }
+ tries++;
+ }, 100);
+ var moveOn = function () {
+ clearInterval(interval);
+ resolve();
+ };
+ });
+}
+
+function nsDoTestsForEditorWithAutoComplete(
+ aDescription,
+ aWindow,
+ aTarget,
+ aAutoCompleteController,
+ aIsFunc,
+ aTodoIsFunc,
+ aGetTargetValueFunc
+) {
+ this._description = aDescription;
+ this._window = aWindow;
+ this._target = aTarget;
+ this._controller = aAutoCompleteController;
+
+ this._is = aIsFunc;
+ this._todo_is = aTodoIsFunc;
+ this._getTargetValue = aGetTargetValueFunc;
+
+ this._target.focus();
+
+ this._DefaultCompleteDefaultIndex =
+ this._controller.input.completeDefaultIndex;
+}
+
+nsDoTestsForEditorWithAutoComplete.prototype = {
+ _window: null,
+ _target: null,
+ _controller: null,
+ _DefaultCompleteDefaultIndex: false,
+ _description: "",
+
+ _is: null,
+ _getTargetValue() {
+ return "not initialized";
+ },
+
+ run: async function runTestsImpl() {
+ for (let test of this._tests) {
+ if (
+ this._controller.input.completeDefaultIndex != test.completeDefaultIndex
+ ) {
+ this._controller.input.completeDefaultIndex = test.completeDefaultIndex;
+ }
+
+ let beforeInputEvents = [];
+ let inputEvents = [];
+ function onBeforeInput(aEvent) {
+ beforeInputEvents.push(aEvent);
+ }
+ function onInput(aEvent) {
+ inputEvents.push(aEvent);
+ }
+ this._target.addEventListener("beforeinput", onBeforeInput);
+ this._target.addEventListener("input", onInput);
+
+ if (test.execute(this._window, this._target) === false) {
+ this._target.removeEventListener("beforeinput", onBeforeInput);
+ this._target.removeEventListener("input", onInput);
+ continue;
+ }
+
+ await waitForCondition(() => {
+ return (
+ this._controller.searchStatus >=
+ Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH
+ );
+ });
+ this._target.removeEventListener("beforeinput", onBeforeInput);
+ this._target.removeEventListener("input", onInput);
+ this._checkResult(test, beforeInputEvents, inputEvents);
+ }
+ this._controller.input.completeDefaultIndex =
+ this._DefaultCompleteDefaultIndex;
+ },
+
+ _checkResult(aTest, aBeforeInputEvents, aInputEvents) {
+ this._is(
+ this._getTargetValue(),
+ aTest.value,
+ this._description + ", " + aTest.description + ": value"
+ );
+ this._is(
+ this._controller.searchString,
+ aTest.searchString,
+ this._description + ", " + aTest.description + ": searchString"
+ );
+ this._is(
+ this._controller.input.popupOpen,
+ aTest.popup,
+ this._description + ", " + aTest.description + ": popupOpen"
+ );
+ this._is(
+ this._controller.searchStatus,
+ Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH,
+ this._description + ", " + aTest.description + ": status"
+ );
+ this._is(
+ aBeforeInputEvents.length,
+ aTest.inputEvents.length,
+ this._description +
+ ", " +
+ aTest.description +
+ ": number of beforeinput events wrong"
+ );
+ this._is(
+ aInputEvents.length,
+ aTest.inputEvents.length,
+ this._description +
+ ", " +
+ aTest.description +
+ ": number of input events wrong"
+ );
+ for (let events of [aBeforeInputEvents, aInputEvents]) {
+ for (let i = 0; i < events.length; i++) {
+ if (aTest.inputEvents[i] === undefined) {
+ this._is(
+ true,
+ false,
+ this._description +
+ ", " +
+ aTest.description +
+ ': "beforeinput" and "input" event shouldn\'t be dispatched anymore'
+ );
+ return;
+ }
+ this._is(
+ events[i] instanceof this._window.InputEvent,
+ true,
+ `${this._description}, ${aTest.description}: "${events[i].type}" event should be dispatched with InputEvent interface`
+ );
+ let expectCancelable =
+ events[i].type === "beforeinput" &&
+ (aTest.inputEvents[i].inputType !== "insertReplacementText" ||
+ SpecialPowers.getBoolPref(
+ "dom.input_event.allow_to_cancel_set_user_input"
+ ));
+
+ this._is(
+ events[i].cancelable,
+ expectCancelable,
+ `${this._description}, ${aTest.description}: "${
+ events[i].type
+ }" event should ${expectCancelable ? "be" : "be never"} cancelable`
+ );
+ this._is(
+ events[i].bubbles,
+ true,
+ `${this._description}, ${aTest.description}: "${events[i].type}" event should always bubble`
+ );
+ this._is(
+ events[i].inputType,
+ aTest.inputEvents[i].inputType,
+ `${this._description}, ${aTest.description}: inputType of "${events[i].type}" event should be "${aTest.inputEvents[i].inputType}"`
+ );
+ this._is(
+ events[i].data,
+ aTest.inputEvents[i].data,
+ `${this._description}, ${aTest.description}: data of "${events[i].type}" event should be ${aTest.inputEvents[i].data}`
+ );
+ this._is(
+ events[i].dataTransfer,
+ null,
+ `${this._description}, ${aTest.description}: dataTransfer of "${events[i].type}" event should be null`
+ );
+ this._is(
+ events[i].getTargetRanges().length,
+ 0,
+ `${this._description}, ${aTest.description}: getTargetRanges() of "${events[i].type}" event should return empty array`
+ );
+ }
+ }
+ },
+
+ _tests: [
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: type 'Mo'",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("M", { shiftKey: true }, aWindow);
+ synthesizeKey("o", {}, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mo",
+ searchString: "Mo",
+ inputEvents: [
+ { inputType: "insertText", data: "M" },
+ { inputType: "insertText", data: "o" },
+ ],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: select 'Mozilla' to complete the word",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("KEY_ArrowDown", {}, aWindow);
+ synthesizeKey("KEY_Enter", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "Mozilla",
+ searchString: "Mozilla",
+ inputEvents: [{ inputType: "insertReplacementText", data: "Mozilla" }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: undo the word, but typed text shouldn't be canceled",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mo",
+ searchString: "Mo",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: undo the typed text",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: redo the typed text",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mo",
+ searchString: "Mo",
+ inputEvents: [{ inputType: "historyRedo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: redo the word",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mozilla",
+ searchString: "Mozilla",
+ inputEvents: [{ inputType: "historyRedo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case: removing all text for next test...",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("a", { accelKey: true }, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "deleteContentBackward", data: null }],
+ },
+
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: type 'mo'",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("m", {}, aWindow);
+ synthesizeKey("o", {}, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mo",
+ searchString: "mo",
+ inputEvents: [
+ { inputType: "insertText", data: "m" },
+ { inputType: "insertText", data: "o" },
+ ],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: select 'Mozilla' to complete the word",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("KEY_ArrowDown", {}, aWindow);
+ synthesizeKey("KEY_Enter", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "Mozilla",
+ searchString: "Mozilla",
+ inputEvents: [{ inputType: "insertReplacementText", data: "Mozilla" }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: undo the word, but typed text shouldn't be canceled",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mo",
+ searchString: "mo",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: undo the typed text",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: redo the typed text",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mo",
+ searchString: "mo",
+ inputEvents: [{ inputType: "historyRedo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: redo the word",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mozilla",
+ searchString: "Mozilla",
+ inputEvents: [{ inputType: "historyRedo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case: removing all text for next test...",
+ completeDefaultIndex: false,
+ execute(aWindow, aTarget) {
+ synthesizeKey("a", { accelKey: true }, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "deleteContentBackward", data: null }],
+ },
+
+ // Testing for nsIAutoCompleteInput.completeDefaultIndex being true.
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): type 'Mo'",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("M", { shiftKey: true }, aWindow);
+ synthesizeKey("o", {}, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mozilla",
+ searchString: "Mo",
+ inputEvents: [
+ { inputType: "insertText", data: "M" },
+ { inputType: "insertText", data: "o" },
+ { inputType: "insertReplacementText", data: "Mozilla" },
+ ],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): select 'Mozilla' to complete the word",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("KEY_ArrowDown", {}, aWindow);
+ synthesizeKey("KEY_Enter", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "Mozilla",
+ searchString: "Mozilla",
+ inputEvents: [],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): undo the word, but typed text shouldn't be canceled",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mo",
+ searchString: "Mo",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): undo the typed text",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): redo the typed text",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mozilla",
+ searchString: "Mo",
+ inputEvents: [
+ { inputType: "historyRedo", data: null },
+ { inputType: "insertReplacementText", data: "Mozilla" },
+ ],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): redo the word",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "Mozilla",
+ searchString: "Mo",
+ inputEvents: [],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text exactly matches the case (completeDefaultIndex is true): removing all text for next test...",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("a", { accelKey: true }, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "deleteContentBackward", data: null }],
+ },
+
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): type 'mo'",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("m", {}, aWindow);
+ synthesizeKey("o", {}, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mozilla",
+ searchString: "mo",
+ inputEvents: [
+ { inputType: "insertText", data: "m" },
+ { inputType: "insertText", data: "o" },
+ { inputType: "insertReplacementText", data: "mozilla" },
+ ],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): select 'Mozilla' to complete the word",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("KEY_ArrowDown", {}, aWindow);
+ synthesizeKey("KEY_Enter", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "Mozilla",
+ searchString: "Mozilla",
+ inputEvents: [{ inputType: "insertReplacementText", data: "Mozilla" }],
+ },
+ // Different from "exactly matches the case" case, modifying the case causes one additional transaction.
+ // Although we could make this transaction ignored.
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): undo the selected word, but typed text shouldn't be canceled",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mozilla",
+ searchString: "mozilla",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): undo the word, but typed text shouldn't be canceled",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mo",
+ searchString: "mo",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): undo the typed text",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("z", { accelKey: true }, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "historyUndo", data: null }],
+ },
+ // XXX This is odd case. Consistency with undo behavior, this should restore "mo".
+ // However, looks like that autocomplete automatically restores "mozilla".
+ // Additionally, looks like that it causes clearing the redo stack.
+ // Therefore, the following redo operations do nothing.
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): redo the typed text",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mozilla",
+ searchString: "mo",
+ inputEvents: [
+ { inputType: "historyRedo", data: null },
+ { inputType: "insertReplacementText", data: "mozilla" },
+ ],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): redo the default index word",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mozilla",
+ searchString: "mo",
+ inputEvents: [],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): redo the word",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("Z", { accelKey: true, shiftKey: true }, aWindow);
+ return true;
+ },
+ popup: true,
+ value: "mozilla",
+ searchString: "mo",
+ inputEvents: [],
+ },
+ {
+ description:
+ "Undo/Redo behavior check when typed text does not match the case (completeDefaultIndex is true): removing all text for next test...",
+ completeDefaultIndex: true,
+ execute(aWindow, aTarget) {
+ synthesizeKey("a", { accelKey: true }, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ return true;
+ },
+ popup: false,
+ value: "",
+ searchString: "",
+ inputEvents: [{ inputType: "deleteContentBackward", data: null }],
+ },
+ ],
+};