mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
2552084ef2
Make the nsAutoCompleteController::HandleDelete() cancel the keypress event if it decides to delete an autocomplete entry. r=gavin
688 lines
18 KiB
HTML
688 lines
18 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<head>
|
|
<title>Test for Form History Autocomplete</title>
|
|
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
|
<script type="text/javascript" src="satchel_common.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
</head>
|
|
<body>
|
|
Form History test: form field autocomplete
|
|
<p id="display"></p>
|
|
|
|
<!-- we presumably can't hide the content for this test. -->
|
|
<div id="content">
|
|
|
|
<!-- normal, basic form -->
|
|
<form id="form1" onsubmit="return false;">
|
|
<input type="text" name="field1">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
<!-- normal, basic form (new fieldname) -->
|
|
<form id="form2" onsubmit="return false;">
|
|
<input type="text" name="field2">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
<!-- form with autocomplete=off on input -->
|
|
<form id="form3" onsubmit="return false;">
|
|
<input type="text" name="field2" autocomplete="off">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
<!-- form with autocomplete=off on form -->
|
|
<form id="form4" autocomplete="off" onsubmit="return false;">
|
|
<input type="text" name="field2">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
<!-- normal form for testing filtering -->
|
|
<form id="form5" onsubmit="return false;">
|
|
<input type="text" name="field3">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
<!-- normal form for testing word boundary filtering -->
|
|
<form id="form6" onsubmit="return false;">
|
|
<input type="text" name="field4">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
<!-- form with maxlength attribute on input -->
|
|
<form id="form7" onsubmit="return false;">
|
|
<input type="text" name="field5" maxlength="10">
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
|
|
</div>
|
|
|
|
<pre id="test">
|
|
<script class="testbody" type="text/javascript">
|
|
|
|
/** Test for Form History autocomplete **/
|
|
|
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
|
|
var input = $_(1, "field1");
|
|
const shiftModifier = Components.interfaces.nsIDOMNSEvent.SHIFT_MASK;
|
|
|
|
// Get the form history service
|
|
var fh = Components.classes["@mozilla.org/satchel/form-history;1"].
|
|
getService(Components.interfaces.nsIFormHistory2);
|
|
ok(fh != null, "got form history service");
|
|
|
|
fh.removeAllEntries();
|
|
fh.addEntry("field1", "value1");
|
|
fh.addEntry("field1", "value2");
|
|
fh.addEntry("field1", "value3");
|
|
fh.addEntry("field1", "value4");
|
|
fh.addEntry("field2", "value1");
|
|
fh.addEntry("field3", "a");
|
|
fh.addEntry("field3", "aa");
|
|
fh.addEntry("field3", "aaz");
|
|
fh.addEntry("field3", "aa\xe6"); // 0xae == latin ae pair (0xc6 == AE)
|
|
fh.addEntry("field3", "az");
|
|
fh.addEntry("field3", "z");
|
|
fh.addEntry("field4", "a\xe6");
|
|
fh.addEntry("field4", "aa a\xe6");
|
|
fh.addEntry("field4", "aba\xe6");
|
|
fh.addEntry("field4", "bc d\xe6");
|
|
fh.addEntry("field5", "1");
|
|
fh.addEntry("field5", "12");
|
|
fh.addEntry("field5", "123");
|
|
fh.addEntry("field5", "1234");
|
|
|
|
|
|
function setForm(value) {
|
|
input.value = value;
|
|
input.focus();
|
|
}
|
|
|
|
// Restore the form to the default state.
|
|
function restoreForm() {
|
|
setForm("");
|
|
}
|
|
|
|
// Check for expected form data.
|
|
function checkForm(expectedValue) {
|
|
var formID = input.parentNode.id;
|
|
is(input.value, expectedValue, "Checking " + formID + " input");
|
|
}
|
|
|
|
|
|
/*
|
|
* Main section of test...
|
|
*
|
|
* This is a bit hacky, because the events are either being sent or
|
|
* processes asynchronously, so we need to interrupt our flow with lots of
|
|
* setTimeout() calls. The case statements are executed in order, one per
|
|
* timeout.
|
|
*/
|
|
function runTest(testNum) {
|
|
// Seems we need to enable this again, or sendKeyEvent() complaints.
|
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
ok(true, "Starting test #" + testNum);
|
|
|
|
switch(testNum) {
|
|
case 1:
|
|
// Make sure initial form is empty.
|
|
checkForm("");
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 2:
|
|
checkMenuEntries(["value1", "value2", "value3", "value4"]);
|
|
// Check first entry
|
|
doKey("down");
|
|
checkForm(""); // value shouldn't update
|
|
doKey("return"); // not "enter"!
|
|
checkForm("value1");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 3:
|
|
// Check second entry
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("return"); // not "enter"!
|
|
checkForm("value2");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 4:
|
|
// Check third entry
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value3");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 5:
|
|
// Check fourth entry
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value4");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 6:
|
|
// Check first entry (wraparound)
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("down"); // deselects
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value1");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 7:
|
|
// Check the last entry via arrow-up
|
|
doKey("up");
|
|
doKey("return");
|
|
checkForm("value4");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 8:
|
|
// Check the last entry via arrow-up
|
|
doKey("down"); // select first entry
|
|
doKey("up"); // selects nothing!
|
|
doKey("up"); // select last entry
|
|
doKey("return");
|
|
checkForm("value4");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 9:
|
|
// Check the last entry via arrow-up (wraparound)
|
|
doKey("down");
|
|
doKey("up"); // deselects
|
|
doKey("up"); // last entry
|
|
doKey("up");
|
|
doKey("up");
|
|
doKey("up"); // first entry
|
|
doKey("up"); // deselects
|
|
doKey("up"); // last entry
|
|
doKey("return");
|
|
checkForm("value4");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 10:
|
|
// Set first entry w/o triggering autocomplete
|
|
doKey("down");
|
|
doKey("right");
|
|
checkForm("value1");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 11:
|
|
// Set first entry w/o triggering autocomplete
|
|
doKey("down");
|
|
doKey("left");
|
|
checkForm("value1");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 12:
|
|
// Check first entry (page up)
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("page_up");
|
|
doKey("return");
|
|
checkForm("value1");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 13:
|
|
// Check last entry (page down)
|
|
doKey("down");
|
|
doKey("page_down");
|
|
doKey("return");
|
|
checkForm("value4");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
testNum = 49;
|
|
break;
|
|
|
|
/* Test removing entries from the dropdown */
|
|
|
|
case 50:
|
|
checkMenuEntries(["value1", "value2", "value3", "value4"]);
|
|
// Delete the first entry (of 4)
|
|
setForm("value");
|
|
doKey("down");
|
|
|
|
// On OS X, shift-backspace and shift-delete work, just delete does not.
|
|
// On Win/Linux, shift-backspace does not work, delete and shift-delete do.
|
|
var osString = Components.classes["@mozilla.org/xre/app-info;1"].
|
|
getService(Components.interfaces.nsIXULRuntime).OS;
|
|
if (osString == "Darwin")
|
|
doKey("back_space", shiftModifier);
|
|
else
|
|
doKey("delete", shiftModifier);
|
|
|
|
// This tests that on OS X shift-backspace didn't delete the last character
|
|
// in the input (bug 480262).
|
|
checkForm("value");
|
|
|
|
ok(!fh.entryExists("field1", "value1"), "checking that f1/v1 was deleted");
|
|
doKey("return");
|
|
checkForm("value2");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 51:
|
|
checkMenuEntries(["value2", "value3", "value4"]);
|
|
// Check the new first entry (of 3)
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value2");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 52:
|
|
// Delete the second entry (of 3)
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("delete", shiftModifier);
|
|
checkForm("");
|
|
ok(!fh.entryExists("field1", "value3"), "checking that f1/v3 was deleted");
|
|
doKey("return");
|
|
checkForm("value4")
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 53:
|
|
checkMenuEntries(["value2", "value4"]);
|
|
// Check the new first entry (of 2)
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value2");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 54:
|
|
// Delete the last entry (of 2)
|
|
doKey("down");
|
|
doKey("down");
|
|
doKey("delete", shiftModifier);
|
|
checkForm("");
|
|
ok(!fh.entryExists("field1", "value4"), "checking that f1/v4 was deleted");
|
|
doKey("return");
|
|
checkForm("value2");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 55:
|
|
checkMenuEntries(["value2"]);
|
|
// Check the new first entry (of 1)
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value2");
|
|
|
|
// Trigger autocomplete popup
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 56:
|
|
// Delete the only remaining entry
|
|
doKey("down");
|
|
doKey("delete", shiftModifier);
|
|
checkForm("");
|
|
ok(!fh.entryExists("field1", "value2"), "checking that f1/v2 was deleted");
|
|
|
|
// Look at form 2, trigger autocomplete popup
|
|
input = $_(2, "field2");
|
|
restoreForm();
|
|
doKey("down");
|
|
testNum = 99;
|
|
break;
|
|
|
|
/* Test entries with autocomplete=off */
|
|
|
|
case 100:
|
|
// Select first entry
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("value1");
|
|
|
|
// Look at form 3, try to trigger autocomplete popup
|
|
input = $_(3, "field2");
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 101:
|
|
// Ensure there's no autocomplete dropdown (autocomplete=off is present)
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("");
|
|
|
|
// Look at form 4, try to trigger autocomplete popup
|
|
input = $_(4, "field2");
|
|
restoreForm();
|
|
doKey("down");
|
|
break;
|
|
|
|
case 102:
|
|
// Ensure there's no autocomplete dropdown (autocomplete=off is present)
|
|
doKey("down");
|
|
doKey("return");
|
|
checkForm("");
|
|
|
|
// Look at form 5, try to trigger autocomplete popup
|
|
input = $_(5, "field3");
|
|
restoreForm();
|
|
testNum = 199;
|
|
sendChar("a", input);
|
|
break;
|
|
|
|
/* Test filtering as characters are typed. */
|
|
|
|
case 200:
|
|
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]);
|
|
sendChar("a", input);
|
|
break;
|
|
|
|
case 201:
|
|
checkMenuEntries(["aa", "aaz", "aa\xe6"]);
|
|
sendChar("\xc6", input);
|
|
break;
|
|
|
|
case 202:
|
|
checkMenuEntries(["aa\xe6"]);
|
|
doKey("back_space");
|
|
break;
|
|
|
|
case 203:
|
|
checkMenuEntries(["aa", "aaz", "aa\xe6"]);
|
|
doKey("back_space");
|
|
break;
|
|
|
|
case 204:
|
|
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]);
|
|
sendChar("z", input);
|
|
break;
|
|
|
|
case 205:
|
|
ok(getMenuEntries().length > 0, "checking typing in middle of text");
|
|
doKey("left");
|
|
sendChar("a", input);
|
|
break;
|
|
|
|
case 206:
|
|
checkMenuEntries(["aaz"]);
|
|
fh.addEntry("field3", "aazq");
|
|
doKey("right");
|
|
sendChar("q", input);
|
|
break;
|
|
|
|
case 207:
|
|
// check that results were cached
|
|
checkMenuEntries([]);
|
|
fh.addEntry("field3", "aazqq");
|
|
sendChar("q", input);
|
|
break;
|
|
|
|
case 208:
|
|
// check that empty results were cached - bug 496466
|
|
checkMenuEntries([]);
|
|
doKey("escape");
|
|
|
|
// Look at form 6, try to trigger autocomplete popup
|
|
input = $_(6, "field4");
|
|
restoreForm();
|
|
testNum = 249;
|
|
sendChar("a", input);
|
|
break;
|
|
|
|
/* Test substring matches and word boundary bonuses */
|
|
|
|
case 250:
|
|
// alphabetical results for first character
|
|
checkMenuEntries(["aa a\xe6", "aba\xe6", "a\xe6"]);
|
|
sendChar("\xc6", input);
|
|
break;
|
|
|
|
case 251:
|
|
// prefix match comes first, then word boundary match
|
|
// followed by substring match
|
|
checkMenuEntries(["a\xe6", "aa a\xe6", "aba\xe6"]);
|
|
|
|
restoreForm();
|
|
sendChar("b", input);
|
|
break;
|
|
|
|
case 252:
|
|
checkMenuEntries(["bc d\xe6"]);
|
|
sendChar(" ", input);
|
|
break;
|
|
|
|
case 253:
|
|
// check that trailing space has no effect after single char.
|
|
checkMenuEntries(["bc d\xe6"]);
|
|
sendChar("\xc6", input);
|
|
break;
|
|
|
|
case 254:
|
|
// check multi-word substring matches
|
|
checkMenuEntries(["bc d\xe6", "aba\xe6"]);
|
|
doKey("left");
|
|
sendChar("d", input);
|
|
break;
|
|
|
|
case 255:
|
|
// check inserting in multi-word searches
|
|
checkMenuEntries(["bc d\xe6"]);
|
|
sendChar("z", input);
|
|
break;
|
|
|
|
case 256:
|
|
checkMenuEntries([]);
|
|
|
|
// Look at form 7, try to trigger autocomplete popup
|
|
input = $_(7, "field5");
|
|
restoreForm();
|
|
doKey("down");
|
|
testNum = 299;
|
|
break;
|
|
|
|
case 300:
|
|
checkMenuEntries(["1", "12", "123", "1234"]);
|
|
input.maxLength = 4;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 301:
|
|
checkMenuEntries(["1", "12", "123", "1234"]);
|
|
input.maxLength = 3;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 302:
|
|
checkMenuEntries(["1", "12", "123"]);
|
|
input.maxLength = 2;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 303:
|
|
checkMenuEntries(["1", "12"]);
|
|
input.maxLength = 1;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 304:
|
|
checkMenuEntries(["1"]);
|
|
input.maxLength = 0;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 305:
|
|
checkMenuEntries([]);
|
|
input.maxLength = 4;
|
|
|
|
// now again with a character typed
|
|
sendChar("1", input);
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 306:
|
|
checkMenuEntries(["1", "12", "123", "1234"]);
|
|
input.maxLength = 3;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 307:
|
|
checkMenuEntries(["1", "12", "123"]);
|
|
input.maxLength = 2;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 308:
|
|
checkMenuEntries(["1", "12"]);
|
|
input.maxLength = 1;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 309:
|
|
checkMenuEntries(["1"]);
|
|
input.maxLength = 0;
|
|
doKey("escape");
|
|
doKey("down");
|
|
break;
|
|
|
|
case 310:
|
|
checkMenuEntries([]);
|
|
|
|
SimpleTest.finish();
|
|
return;
|
|
|
|
default:
|
|
ok(false, "Unexpected invocation of test #" + testNum);
|
|
SimpleTest.finish();
|
|
return;
|
|
}
|
|
|
|
setTimeout(runTest, 50, testNum + 1); // XXX 40ms was too slow, why?
|
|
}
|
|
|
|
function checkMenuEntries(expectedValues) {
|
|
var actualValues = getMenuEntries();
|
|
is(actualValues.length, expectedValues.length, "Checking length of expected menu");
|
|
for (var i = 0; i < expectedValues.length; i++)
|
|
is(actualValues[i], expectedValues[i], "Checking menu entry #"+i);
|
|
}
|
|
|
|
var autocompleteMenu;
|
|
function getMenuEntries() {
|
|
var entries = [];
|
|
|
|
// Could perhaps pull values directly from the controller, but it seems
|
|
// more reliable to test the values that are actually in the tree?
|
|
var column = autocompleteMenu.tree.columns[0];
|
|
var numRows = autocompleteMenu.tree.view.rowCount;
|
|
for (var i = 0; i < numRows; i++) {
|
|
entries.push(autocompleteMenu.tree.view.getValueAt(i, column));
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
function startTest() {
|
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
var Ci = Components.interfaces;
|
|
chromeWin = window
|
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
|
.rootTreeItem
|
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIDOMWindow)
|
|
.QueryInterface(Ci.nsIDOMChromeWindow);
|
|
autocompleteMenu = chromeWin.document.getElementById("PopupAutoComplete");
|
|
ok(autocompleteMenu, "Got autocomplete popup");
|
|
runTest(1);
|
|
}
|
|
|
|
window.onload = startTest;
|
|
|
|
SimpleTest.waitForExplicitFinish();
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|
|
|