gecko/toolkit/components/satchel/test/test_form_autocomplete.html

814 lines
20 KiB
HTML

<!DOCTYPE HTML>
<html>
<head>
<title>Test for Form History Autocomplete</title>
<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>
<!-- form with input type='email' -->
<form id="form8" onsubmit="return false;">
<input type="email" name="field6">
<button type="submit">Submit</button>
</form>
<!-- form with input type='tel' -->
<form id="form9" onsubmit="return false;">
<input type="tel" name="field7">
<button type="submit">Submit</button>
</form>
<!-- form with input type='url' -->
<form id="form10" onsubmit="return false;">
<input type="url" name="field8">
<button type="submit">Submit</button>
</form>
<!-- form with input type='search' -->
<form id="form11" onsubmit="return false;">
<input type="search" name="field9">
<button type="submit">Submit</button>
</form>
<!-- form with input type='number' -->
<form id="form12" onsubmit="return false;">
<input type="number" name="field10">
<button type="submit">Submit</button>
</form>
<!-- normal, basic form (with fieldname='searchbar-history') -->
<form id="form13" onsubmit="return false;">
<input type="text" name="searchbar-history">
<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.nsIDOMEvent.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");
fh.addEntry("field6", "value");
fh.addEntry("field7", "value");
fh.addEntry("field8", "value");
fh.addEntry("field9", "value");
fh.addEntry("field10", "42");
fh.addEntry("searchbar-history", "blacklist test");
// All these non-implemeted types might need autocomplete tests in the future.
var todoTypes = [ "datetime", "date", "month", "week", "time", "datetime-local",
"range", "color" ];
var todoInput = document.createElement("input");
for each (var type in todoTypes) {
todoInput.type = type;
todo_is(todoInput.type, type, type + " type shouldn't be implemented");
}
function setForm(value) {
input.value = value;
input.focus();
}
var autocompleteMenu = getAutocompletePopup();
// 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
* processed 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;
input.focus();
sendChar("a");
break;
/* Test filtering as characters are typed. */
case 200:
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]);
input.focus();
sendChar("a");
break;
case 201:
checkMenuEntries(["aa", "aaz", "aa\xe6"]);
input.focus();
sendChar("\xc6");
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"]);
input.focus();
sendChar("z");
break;
case 205:
ok(getMenuEntries().length > 0, "checking typing in middle of text");
input.focus();
doKey("left");
sendChar("a");
break;
case 206:
checkMenuEntries(["aaz"]);
fh.addEntry("field3", "aazq");
input.focus();
doKey("right");
sendChar("q");
break;
case 207:
// check that results were cached
checkMenuEntries([]);
fh.addEntry("field3", "aazqq");
input.focus();
sendChar("q");
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;
input.focus();
sendChar("a");
break;
/* Test substring matches and word boundary bonuses */
case 250:
// alphabetical results for first character
checkMenuEntries(["aa a\xe6", "aba\xe6", "a\xe6"]);
input.focus();
sendChar("\xc6");
break;
case 251:
// prefix match comes first, then word boundary match
// followed by substring match
checkMenuEntries(["a\xe6", "aa a\xe6", "aba\xe6"]);
restoreForm();
input.focus();
sendChar("b");
break;
case 252:
checkMenuEntries(["bc d\xe6"]);
input.focus();
sendChar(" ");
break;
case 253:
// check that trailing space has no effect after single char.
checkMenuEntries(["bc d\xe6"]);
input.focus();
sendChar("\xc6");
break;
case 254:
// check multi-word substring matches
checkMenuEntries(["bc d\xe6", "aba\xe6"]);
input.focus();
doKey("left");
sendChar("d");
break;
case 255:
// check inserting in multi-word searches
checkMenuEntries(["bc d\xe6"]);
input.focus();
sendChar("z");
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
input.focus();
sendChar("1");
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([]);
input = $_(8, "field6");
testNum = 399;
restoreForm();
doKey("down");
break;
case 400:
case 401:
case 402:
case 403:
checkMenuEntries(["value"]);
doKey("down");
doKey("return");
checkForm("value");
if (testNum == 400) {
input = $_(9, "field7");
} else if (testNum == 401) {
input = $_(10, "field8");
} else if (testNum == 402) {
input = $_(11, "field9");
} else if (testNum == 403) {
input = $_(12, "field10");
}
restoreForm();
doKey("down");
break;
case 404:
checkMenuEntries(["42"]);
doKey("down");
doKey("return");
checkForm("42");
// Go to test 500.
fh.addEntry("field1", "value1");
input = $_(1, "field1");
testNum = 499;
restoreForm();
doKey("down");
break;
// Check that the input event is fired.
case 500:
input.addEventListener("input", function(event) {
input.removeEventListener("input", arguments.callee, false);
ok(true, "oninput should have been received");
ok(event.bubbles, "input event should bubble");
ok(event.cancelable, "input event should be cancelable");
}, false);
doKey("down");
checkForm("");
doKey("return");
checkForm("value1");
testNum = 599;
break;
case 600:
// check we don't show autocomplete for searchbar-history
input = $_(13, "searchbar-history");
// Trigger autocomplete popup
checkForm("");
restoreForm();
doKey("down");
break;
case 601:
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);
}
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() {
runTest(1);
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>