mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-18 14:56:07 +00:00
Bug 722961 Add tests for autocomplete with composition r=m_kato
This commit is contained in:
parent
9db2c07418
commit
0582e6722b
@ -65,7 +65,6 @@ _TEST_FILES = \
|
||||
test_bug645914.html \
|
||||
test_bug681229.html \
|
||||
test_bug692520.html \
|
||||
test_bug717147.html \
|
||||
test_dom_input_event_on_texteditor.html \
|
||||
$(NULL)
|
||||
|
||||
|
@ -1,99 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=717147
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 717147</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717147">Mozilla Bug 717147</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<iframe id="formTarget" name="formTarget"></iframe>
|
||||
<form action="data:text/html," target="formTarget">
|
||||
<input name="test" id="initValue"><input type="submit">
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 717147 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var formTarget = document.getElementById("formTarget");
|
||||
var initValue = document.getElementById("initValue");
|
||||
|
||||
formTarget.addEventListener("load", function() {
|
||||
var newInput = document.createElement("input");
|
||||
newInput.setAttribute("name", "test");
|
||||
document.body.appendChild(newInput);
|
||||
|
||||
setTimeout(function() {
|
||||
var popupShown = false;
|
||||
function listener() {
|
||||
popupShown = true;
|
||||
}
|
||||
SpecialPowers.addAutoCompletePopupEventListener(window, listener);
|
||||
|
||||
newInput.value = "";
|
||||
newInput.focus();
|
||||
|
||||
synthesizeComposition({ type: "compositionstart" });
|
||||
synthesizeComposition({ type: "compositionupdate", data: "f" });
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "f",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
hitEventLoop(function() {
|
||||
ok(!popupShown, "Popup must not be opened during composition");
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "f",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
synthesizeComposition({ type: "compositionend", data: "f" });
|
||||
|
||||
hitEventLoop(function () {
|
||||
ok(popupShown, "Popup must be opened after compositionend");
|
||||
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, listener);
|
||||
SimpleTest.finish();
|
||||
}, 100);
|
||||
}, 100);
|
||||
}, 0);
|
||||
}, false);
|
||||
|
||||
initValue.focus();
|
||||
initValue.value = "foo";
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
});
|
||||
|
||||
function hitEventLoop(func, times) {
|
||||
if (times > 0) {
|
||||
setTimeout(hitEventLoop, 0, func, times - 1);
|
||||
} else {
|
||||
setTimeout(func, 0);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -704,6 +704,18 @@ SpecialPowersAPI.prototype = {
|
||||
listener,
|
||||
false);
|
||||
},
|
||||
getFormFillController: function(window) {
|
||||
return Components.classes["@mozilla.org/satchel/form-fill-controller;1"]
|
||||
.getService(Components.interfaces.nsIFormFillController);
|
||||
},
|
||||
attachFormFillControllerTo: function(window) {
|
||||
this.getFormFillController()
|
||||
.attachToBrowser(this._getDocShell(window),
|
||||
this._getAutoCompletePopup(window));
|
||||
},
|
||||
detachFormFillControllerFrom: function(window) {
|
||||
this.getFormFillController().detachFromBrowser(this._getDocShell(window));
|
||||
},
|
||||
isBackButtonEnabled: function(window) {
|
||||
return !this._getTopChromeWindow(window).document
|
||||
.getElementById("Browser:Back")
|
||||
|
@ -89,6 +89,9 @@ _TEST_FILES = findbar_window.xul \
|
||||
test_autocomplete4.xul \
|
||||
test_autocomplete5.xul \
|
||||
test_autocomplete_delayOnPaste.xul \
|
||||
file_autocomplete_with_composition.js \
|
||||
test_autocomplete_with_composition_on_input.html \
|
||||
test_autocomplete_with_composition_on_textbox.xul \
|
||||
test_keys.xul \
|
||||
window_keys.xul \
|
||||
test_showcaret.xul \
|
||||
|
@ -0,0 +1,633 @@
|
||||
// nsDoTestsForAutoCompleteWithComposition tests autocomplete with composition.
|
||||
// Users must include SimpleTest.js and EventUtils.js.
|
||||
|
||||
function nsDoTestsForAutoCompleteWithComposition(aDescription,
|
||||
aWindow,
|
||||
aTarget,
|
||||
aAutoCompleteController,
|
||||
aIsFunc,
|
||||
aGetTargetValueFunc,
|
||||
aOnFinishFunc)
|
||||
{
|
||||
this._description = aDescription;
|
||||
this._window = aWindow;
|
||||
this._target = aTarget;
|
||||
this._controller = aAutoCompleteController;
|
||||
|
||||
this._is = aIsFunc;
|
||||
this._getTargetValue = aGetTargetValueFunc;
|
||||
this._onFinish = aOnFinishFunc;
|
||||
|
||||
this._target.focus();
|
||||
|
||||
this._DefaultCompleteDefaultIndex =
|
||||
this._controller.input.completeDefaultIndex;
|
||||
|
||||
this._doTests();
|
||||
}
|
||||
|
||||
nsDoTestsForAutoCompleteWithComposition.prototype = {
|
||||
_window: null,
|
||||
_target: null,
|
||||
_controller: null,
|
||||
_DefaultCompleteDefaultIndex: false,
|
||||
_description: "",
|
||||
|
||||
_is: null,
|
||||
_getTargetValue: function () { return "not initialized"; },
|
||||
_onFinish: null,
|
||||
|
||||
_doTests: function ()
|
||||
{
|
||||
if (++this._testingIndex == this._tests.length) {
|
||||
this._controller.input.completeDefaultIndex =
|
||||
this._DefaultCompleteDefaultIndex;
|
||||
this._onFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = this._tests[this._testingIndex];
|
||||
if (this._controller.input.completeDefaultIndex != test.completeDefaultIndex) {
|
||||
this._controller.input.completeDefaultIndex = test.completeDefaultIndex;
|
||||
}
|
||||
test.execute(this._window);
|
||||
|
||||
var timeout = this._controller.input.timeout + 10;
|
||||
this._waitResult(timeout);
|
||||
},
|
||||
|
||||
_waitResult: function (aTimes)
|
||||
{
|
||||
var obj = this;
|
||||
if (aTimes-- > 0) {
|
||||
setTimeout(function () { obj._waitResult(aTimes); }, 0);
|
||||
} else {
|
||||
setTimeout(function () { obj._checkResult(); }, 0);
|
||||
}
|
||||
},
|
||||
|
||||
_checkResult: function ()
|
||||
{
|
||||
var test = this._tests[this._testingIndex];
|
||||
this._is(this._getTargetValue(), test.value,
|
||||
this._description + ", " + test.description + ": value");
|
||||
this._is(this._controller.searchString, test.searchString,
|
||||
this._description + ", " + test.description +": searchString");
|
||||
this._is(this._controller.input.popupOpen, test.popup,
|
||||
this._description + ", " + test.description + ": popupOpen");
|
||||
this._doTests();
|
||||
},
|
||||
|
||||
_testingIndex: -1,
|
||||
_tests: [
|
||||
// Simple composition when popup hasn't been shown.
|
||||
// The autocomplete popup should not be shown during composition, but
|
||||
// after compositionend, the popup should be shown.
|
||||
{ description: "compositionstart shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "M" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "M",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "M", searchString: ""
|
||||
},
|
||||
{ description: "compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "Mo" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "Mo",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: ""
|
||||
},
|
||||
{ description: "compositionend should open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "Mo",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "Mo" }, aWindow);
|
||||
synthesizeKey("VK_ENTER", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "Mo", searchString: "Mo"
|
||||
},
|
||||
// If composition starts when popup is shown, the compositionstart event
|
||||
// should cause closing the popup.
|
||||
{ description: "compositionstart should close the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("z", { type: "keydown" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "z" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "z",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Moz", searchString: "Mo"
|
||||
},
|
||||
{ description: "compositionupdate shouldn't reopen the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "zi" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "zi",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mozi", searchString: "Mo"
|
||||
},
|
||||
{ description: "compositionend should research the result and open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "zi",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
synthesizeComposition({ type: "compositionend", data: "zi" }, aWindow);
|
||||
synthesizeKey("VK_ENTER", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "Mozi", searchString: "Mozi"
|
||||
},
|
||||
// If composition is cancelled, the value shouldn't be changed.
|
||||
{ description: "compositionstart should reclose the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("l", { type: "keydown" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "l" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "l",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mozil", searchString: "Mozi"
|
||||
},
|
||||
{ description: "compositionupdate shouldn't reopen the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "ll" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "ll",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mozill", searchString: "Mozi"
|
||||
},
|
||||
{ description: "empty compositionupdate shouldn't reopen the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mozi", searchString: "Mozi"
|
||||
},
|
||||
{ description: "cancled compositionend should reopen the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "" }, aWindow);
|
||||
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "Mozi", searchString: "Mozi"
|
||||
},
|
||||
// But if composition replaces some characters and canceled, the search
|
||||
// string should be the latest value.
|
||||
{ description: "compositionstart with selected string should close the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
|
||||
synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
|
||||
synthesizeKey("z", { type: "keydown" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "z" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "z",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Moz", searchString: "Mozi"
|
||||
},
|
||||
{ description: "compositionupdate shouldn't reopen the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "ll" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "zi",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mozi", searchString: "Mozi"
|
||||
},
|
||||
{ description: "empty compositionupdate shouldn't reopen the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: "Mozi"
|
||||
},
|
||||
{ description: "canceled compositionend should seach the result with the latest value",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "" }, aWindow);
|
||||
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "Mo", searchString: "Mo"
|
||||
},
|
||||
//If all characters are removed, the popup should be closed.
|
||||
{ description: "the value becomes empty by backspace, the popup should be closed",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
}, popup: false, value: "", searchString: ""
|
||||
},
|
||||
// composition which is canceled shouldn't cause opening the popup.
|
||||
{ description: "compositionstart shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "M" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "M",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "M", searchString: ""
|
||||
},
|
||||
{ description: "compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "Mo" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "Mo",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: ""
|
||||
},
|
||||
{ description: "empty compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "", searchString: ""
|
||||
},
|
||||
{ description: "canceled compositionend shouldn't open the popup if it was closed",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "" }, aWindow);
|
||||
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
|
||||
}, popup: false, value: "", searchString: ""
|
||||
},
|
||||
// Down key should open the popup even if the editor is empty.
|
||||
{ description: "DOWN key should open the popup even if the value is empty",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("VK_DOWN", {}, aWindow);
|
||||
}, popup: true, value: "", searchString: ""
|
||||
},
|
||||
// If popup is open at starting composition, the popup should be reopened
|
||||
// after composition anyway.
|
||||
{ description: "compositionstart shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "M" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "M",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "M", searchString: ""
|
||||
},
|
||||
{ description: "compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "Mo" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "Mo",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: ""
|
||||
},
|
||||
{ description: "empty compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "", searchString: ""
|
||||
},
|
||||
{ description: "canceled compositionend should open the popup if it was opened",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "" }, aWindow);
|
||||
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "", searchString: ""
|
||||
},
|
||||
// Type normally, and hit escape, the popup should be closed.
|
||||
{ description: "ESCAPE should close the popup after typing something",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("M", { shiftKey: true }, aWindow);
|
||||
synthesizeKey("o", { shiftKey: true }, aWindow);
|
||||
synthesizeKey("VK_ESCAPE", {}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: "Mo"
|
||||
},
|
||||
// Even if the popup is closed, composition which is canceled should open
|
||||
// the popup if the value isn't empty.
|
||||
// XXX This might not be good behavior, but anyway, this is minor issue...
|
||||
{ description: "compositionstart shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("z", { type: "keydown", shiftKey: true }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "z" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "z",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Moz", searchString: "Mo"
|
||||
},
|
||||
{ description: "compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "zi" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "zi",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mozi", searchString: "Mo"
|
||||
},
|
||||
{ description: "empty compositionupdate shouldn't open the popup",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: "Mo"
|
||||
},
|
||||
{ description: "canceled compositionend shouldn't open the popup if the popup was closed",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "" }, aWindow);
|
||||
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "Mo", searchString: "Mo"
|
||||
},
|
||||
// House keeping...
|
||||
{ description: "house keeping for next tests",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
}, popup: false, value: "", searchString: ""
|
||||
},
|
||||
// Testing for nsIAutoCompleteInput.completeDefaultIndex being true.
|
||||
{ description: "compositionstart shouldn't open the popup (completeDefaultIndex is true)",
|
||||
completeDefaultIndex: true,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
|
||||
synthesizeComposition({ type: "compositionstart" }, aWindow);
|
||||
synthesizeComposition({ type: "compositionupdate", data: "M" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "M",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "M", searchString: ""
|
||||
},
|
||||
{ description: "compositionupdate shouldn't open the popup (completeDefaultIndex is true)",
|
||||
completeDefaultIndex: true,
|
||||
execute: function (aWindow) {
|
||||
synthesizeComposition({ type: "compositionupdate", data: "Mo" }, aWindow);
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "Mo",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
}, popup: false, value: "Mo", searchString: ""
|
||||
},
|
||||
{ description: "compositionend should open the popup (completeDefaultIndex is true)",
|
||||
completeDefaultIndex: true,
|
||||
execute: function (aWindow) {
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "Mo",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
}, aWindow);
|
||||
synthesizeComposition({ type: "compositionend", data: "Mo" }, aWindow);
|
||||
synthesizeKey("VK_ENTER", { type: "keyup" }, aWindow);
|
||||
}, popup: true, value: "Mozilla", searchString: "Mo"
|
||||
},
|
||||
// House keeping...
|
||||
{ description: "house keeping for next tests",
|
||||
completeDefaultIndex: false,
|
||||
execute: function (aWindow) {
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWindow);
|
||||
}, popup: false, value: "", searchString: ""
|
||||
}
|
||||
]
|
||||
};
|
@ -0,0 +1,65 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>autocomplete with composition tests on HTML input element</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
|
||||
<script type="text/javascript" src="file_autocomplete_with_composition.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<div id="content">
|
||||
<iframe id="formTarget" name="formTarget"></iframe>
|
||||
<form action="data:text/html," target="formTarget">
|
||||
<input name="test" id="input"><input type="submit">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var formFillController =
|
||||
SpecialPowers.getFormFillController()
|
||||
.QueryInterface(Components.interfaces.nsIAutoCompleteInput);
|
||||
var originalFormFillTimeout = formFillController.timeout;
|
||||
|
||||
SpecialPowers.attachFormFillControllerTo(window);
|
||||
var target = document.getElementById("input");
|
||||
|
||||
// Register a word to the form history.
|
||||
target.focus();
|
||||
target.value = "Mozilla";
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
target.value = "";
|
||||
|
||||
var test1 = new nsDoTestsForAutoCompleteWithComposition(
|
||||
"Testing on HTML input (asynchronously search)",
|
||||
window, target, formFillController.controller, is,
|
||||
function () { return target.value; },
|
||||
function () {
|
||||
target.setAttribute("timeout", 0);
|
||||
var test2 = new nsDoTestsForAutoCompleteWithComposition(
|
||||
"Testing on HTML input (synchronously search)",
|
||||
window, target, formFillController.controller, is,
|
||||
function () { return target.value; },
|
||||
function () {
|
||||
formFillController.timeout = originalFormFillTimeout;
|
||||
SpecialPowers.detachFormFillControllerFrom(window);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(runTests);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,125 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Testing autocomplete with composition"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js" />
|
||||
<script type="text/javascript"
|
||||
src="file_autocomplete_with_composition.js" />
|
||||
|
||||
<textbox id="textbox" type="autocomplete"
|
||||
autocompletesearch="simpleForComposition"/>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const nsIAutoCompleteResult = Components.interfaces.nsIAutoCompleteResult;
|
||||
|
||||
// This result can't be constructed in-line, because otherwise we leak memory.
|
||||
function nsAutoCompleteSimpleResult(aString)
|
||||
{
|
||||
this.searchString = aString;
|
||||
if (aString == "" || aString == "Mozilla".substr(0, aString.length)) {
|
||||
this.searchResult = nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
this.matchCount = 1;
|
||||
this._value = "Mozilla";
|
||||
} else {
|
||||
this.searchResult = nsIAutoCompleteResult.RESULT_NOMATCH;
|
||||
this.matchCount = 0;
|
||||
this._value = "";
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCompleteSimpleResult.prototype = {
|
||||
_value: "",
|
||||
searchString: null,
|
||||
searchResult: nsIAutoCompleteResult.RESULT_FAILURE,
|
||||
defaultIndex: 0,
|
||||
errorDescription: null,
|
||||
matchCount: 0,
|
||||
getValueAt: function(aIndex) { return aIndex == 0 ? this._value : null; },
|
||||
getCommentAt: function() { return null; },
|
||||
getStyleAt: function() { return null; },
|
||||
getImageAt: function() { return null; },
|
||||
getLabelAt: function() { return null; },
|
||||
removeValueAt: function() {}
|
||||
};
|
||||
|
||||
// A basic autocomplete implementation that either returns one result or none
|
||||
var autoCompleteSimpleID =
|
||||
Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
|
||||
var autoCompleteSimpleName =
|
||||
"@mozilla.org/autocomplete/search;1?name=simpleForComposition"
|
||||
var autoCompleteSimple = {
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Components.interfaces.nsISupports) ||
|
||||
iid.equals(Components.interfaces.nsIFactory) ||
|
||||
iid.equals(Components.interfaces.nsIAutoCompleteSearch))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
startSearch: function(aString, aParam, aResult, aListener) {
|
||||
var result = new nsAutoCompleteSimpleResult(aString);
|
||||
aListener.onSearchResult(this, result);
|
||||
},
|
||||
|
||||
stopSearch: function() {}
|
||||
};
|
||||
|
||||
var componentManager =
|
||||
Components.manager
|
||||
.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(autoCompleteSimpleID,
|
||||
"Test Simple Autocomplete for composition",
|
||||
autoCompleteSimpleName, autoCompleteSimple);
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var target = document.getElementById("textbox");
|
||||
target.setAttribute("timeout", 1);
|
||||
var test1 = new nsDoTestsForAutoCompleteWithComposition(
|
||||
"Testing on XUL textbox (asynchronously search)",
|
||||
window, target, target.controller, is,
|
||||
function () { return target.value; },
|
||||
function () {
|
||||
target.setAttribute("timeout", 0);
|
||||
var test2 = new nsDoTestsForAutoCompleteWithComposition(
|
||||
"Testing on XUL textbox (synchronously search)",
|
||||
window, target, target.controller, is,
|
||||
function () { return target.value; },
|
||||
function () {
|
||||
// Unregister the factory so that we don't get in the way of other
|
||||
// tests
|
||||
componentManager.unregisterFactory(autoCompleteSimpleID,
|
||||
autoCompleteSimple);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(runTests);
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
Loading…
x
Reference in New Issue
Block a user