Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE HTML>
<html>
<head>
<title>Test for Form History Autocomplete</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script 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">
<datalist id="suggest">
<option value="Google" label="PASS1">FAIL</option>
<option value="Reddit">PASS2</option>
<option value="final"></option>
</datalist>
<!-- normal, basic form -->
<form id="form1">
<input list="suggest" type="text" name="field1">
<button type="submit">Submit</button>
</form>
<!-- form with autocomplete=off on input -->
<form id="form3">
<input list="suggest" type="text" name="field2" autocomplete="off">
<button type="submit">Submit</button>
</form>
<!-- form with autocomplete=off on form -->
<form id="form4" autocomplete="off">
<input list="suggest" type="text" name="field2">
<button type="submit">Submit</button>
</form>
<!-- yet another normal, basic form, with 2 history entries -->
<form id="form5">
<input list="suggest" type="text" name="field3">
<button type="submit">Submit</button>
</form>
<form id="show_datalist_for_text_inputs_only">
<input list="suggest" type="button" popup="false" />
<input list="suggest" type="checkbox" popup="false" />
<input list="suggest" type="color" popup="false" />
<input list="suggest" type="date" popup="false" />
<input list="suggest" type="datetime-local" popup="false" />
<input list="suggest" type="email" popup="true" />
<input list="suggest" type="file" popup="false" />
<input list="suggest" type="image" popup="false" />
<input list="suggest" type="month" popup="true" />
<input list="suggest" type="number" popup="false" />
<input list="suggest" type="password" popup="true" />
<input list="suggest" type="radio" popup="false" />
<input list="suggest" type="range" popup="false" />
<input list="suggest" type="reset" popup="false" />
<input list="suggest" type="search" popup="true" />
<input list="suggest" type="submit" popup="false" />
<input list="suggest" type="tel" popup="true" />
<input list="suggest" type="text" popup="true" />
<input list="suggest" type="time" popup="false" />
<input list="suggest" type="url" popup="true" />
<input list="suggest" type="week" popup="true" />
</form>
</div>
<script>
preventSubmitOnForms();
add_setup(async () => {
await updateFormHistory([
{ op: "remove" },
{ op: "add", fieldname: "field1", value: "historyvalue" },
{ op: "add", fieldname: "field2", value: "othervalue" },
{ op: "add", fieldname: "field3", value: "history1" },
{ op: "add", fieldname: "field3", value: "history2" },
]);
});
add_task(async function no_changes_when_opening_popup(){
const { input } = await openPopupOn("#form1 > input");
assertValueAfterKeys(input, [], "");
});
add_task(async function use_1st_entry() {
const { input } = await openPopupOn("#form1 > input");
assertAutocompleteItems("historyvalue", "PASS1", "PASS2", "final");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"historyvalue");
});
add_task(async function use_2nd_entry(){
const { input } = await openPopupOn("#form1 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"Google");
});
add_task(async function use_3rd_entry(){
const { input } = await openPopupOn("#form1 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"Reddit");
});
add_task(async function use_4th_entry(){
const { input } = await openPopupOn("#form1 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"final");
});
add_task(async function delete_1st_entry(){
const { input } = await openPopupOn("#form1 > input");
assertValueAfterKeys(input, "KEY_ArrowDown", "");
deleteSelectedAutocompleteItem();
await notifyMenuChanged(3);
is(await countEntries("field1", "historyvalue"), 0, "item is absent");
});
add_task(async function can_use_next_item_after_deletion(){
const { input } = await openPopupOn("#form1 > input");
assertAutocompleteItems("PASS1", "PASS2", "final");
assertValueAfterKeys(input, ["KEY_ArrowDown", "KEY_Enter"], "Google");
});
add_task(async function autocomplete_on_datalist_with_cached_results(){
const { input } = await openPopupOn("#form1 > input");
sendString("PAS");
await notifyMenuChanged(2);
sendString("S1");
await notifyMenuChanged(1);
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"Google");
});
add_task(async function fills_with_autocomplete_off_on_form(){
const { input } = await openPopupOn("#form4 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"Google");
assertAutocompleteItems("PASS1", "PASS2", "final");
});
add_task(async function use_1st_entry_with_autocomplete_off_on_form(){
const { input } = await openPopupOn("#form4 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"Google");
});
add_task(async function use_2nd_entry_with_autocomplete_off_on_form(){
const { input } = await openPopupOn("#form4 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"Reddit");
});
add_task(async function use_3rd_entry_with_autocomplete_off_on_form(){
const { input } = await openPopupOn("#form4 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"final");
});
add_task(async function fills_with_autocomplete_off_on_input(){
const { input } = await openPopupOn("#form3 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"Google");
assertAutocompleteItems("PASS1", "PASS2", "final");
});
add_task(async function use_1st_entry_with_autocomplete_off_on_input(){
const { input } = await openPopupOn("#form3 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"Google");
});
add_task(async function use_2nd_entry_with_autocomplete_off_on_input(){
const { input } = await openPopupOn("#form3 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"Reddit");
});
add_task(async function use_3rd_entry_with_autocomplete_off_on_input(){
const { input } = await openPopupOn("#form3 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"final");
});
add_task(async function remove_item_from_datalist(){
// When there is an update of the list, the selection is lost so we need to
// go down like if we were at the beginning of the list again.
//
// Removing the second element while on the first then going down and
// push enter. Value should be one from the third suggesion.
const { input } = await openPopupOn("#form3 > input");
synthesizeKey("KEY_ArrowDown");
const datalist = document.getElementById("suggest");
const toRemove = datalist.children[1];
datalist.removeChild(toRemove);
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"final");
// Restore the element.
datalist.insertBefore(toRemove, datalist.children[1]);
});
add_task(async function add_item_to_datalist(){
const { input } = await openPopupOn("#form3 > input");
const datalist = document.getElementById("suggest");
// Adding an attribute after the first one while on the first then going
// down and push enter. Value should be the on from the new suggestion.
synthesizeKey("KEY_ArrowDown");
datalist.insertBefore(new Option("New value"), datalist.children[1]);
await notifyMenuChanged(4);
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"New value");
});
add_task(async function change_datalist_option_value(){
const datalist = document.getElementById("suggest");
// Remove the element.
datalist.removeChild(datalist.children[1]);
await notifyMenuChanged(0);
// Change the first element value attribute.
const prevValue = datalist.children[0].value;
datalist.children[0].value = "foo";
const { input } = await openPopupOn("#form3 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"foo");
datalist.children[0].value = prevValue;
await notifyMenuChanged(0);
});
add_task(async function change_datalist_option_text_content(){
const datalist = document.getElementById("suggest");
const prevValue = datalist.children[0].getAttribute("value");
datalist.children[0].removeAttribute("value");
datalist.children[0].textContent = "foobar";
const { input } = await openPopupOn("#form3 > input");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_Enter"],
"foobar");
datalist.children[0].setAttribute("value", prevValue);
await notifyMenuChanged(0);
});
add_task(async function filters_with_1st_letter(){
const { input } = await openPopupOn("#form3 > input");
sendString("f");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"final");
});
add_task(async function filters_with_letter_in_the_middle(){
const { input } = await openPopupOn("#form3 > input");
sendString("in");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown", "KEY_Enter"],
"final");
});
add_task(async function input_events(){
const { input } = await openPopupOn("#form3 > input");
let beforeInputFired = false;
input.addEventListener("beforeinput", (event) => {
beforeInputFired = true;
ok(event instanceof InputEvent, "beforeinput event has InputEvent interface");
ok(event.bubbles, "beforeinput event should bubble");
is(
event.cancelable,
SpecialPowers.getBoolPref("dom.input_event.allow_to_cancel_set_user_input"),
"beforeinput event for insertReplacementText should be cancelable if not suppressed");
is(event.inputType, "insertReplacementText", "inputType of beforeinput event should be insertReplacementText");
is(event.data, "Google", "data of beforeinput event should be Google");
is(event.dataTransfer, null, "dataTransfer of beforeinput event should be null");
is(event.getTargetRanges().length, 0, "getTargetRanges() of beforeinput event should be empty array");
}, { once: true });
let inputFired = false;
input.addEventListener("input", function(event) {
inputFired = true;
ok(event instanceof InputEvent,
"input event should be dispatched with InputEvent interface");
ok(event.bubbles, "input event should bubble");
ok(!event.cancelable, "input event should be cancelable");
is(event.inputType, "insertReplacementText", "inputType of input event should be insertReplacementText");
is(event.data, "Google", "data of input event should be Google");
is(event.dataTransfer, null, "dataTransfer of input event should be null");
is(event.getTargetRanges().length, 0, "getTargetRanges() of input event should be empty array");
}, { once: true });
assertValueAfterKeys(input, ["KEY_ArrowDown", "KEY_Enter"], "Google");
ok(beforeInputFired, "beforeinput event should've been fired");
ok(inputFired, "input event should've been fired");
});
add_task(async function cancelled_beforeinput_event(){
const { input } = await openPopupOn("#form3 > input");
await SpecialPowers.pushPrefEnv({
set: [["dom.input_event.allow_to_cancel_set_user_input", true]],
});
input.addEventListener("beforeinput", e => e.preventDefault(), { once: true });
let inputFired = false;
input.addEventListener("input", () => inputFired = true, { once: true });
assertValueAfterKeys(input, "KEY_ArrowDown", "");
assertValueAfterKeys(input, "KEY_Enter", "");
ok(!inputFired, "no input event when beforeinput is canceled");
input.blur();
await SpecialPowers.pushPrefEnv({
clear: [["dom.input_event.allow_to_cancel_set_user_input"]],
});
});
add_task(async function attempt_to_delete_datalist_entries(){
const { input } = await openPopupOn("#form5 > input");
assertAutocompleteItems("history1", "history2", "PASS1", "PASS2", "final");
assertValueAfterKeys(
input,
["KEY_ArrowDown", "KEY_ArrowDown", "KEY_ArrowDown"],
"");
deleteSelectedAutocompleteItem();
synthesizeKey("KEY_ArrowUp");
deleteSelectedAutocompleteItem();
await notifyMenuChanged(4);
assertAutocompleteItems("history1", "PASS1", "PASS2", "final");
// Delete the second entry, that is the 1st entry of datalist.
// This has no effect.
deleteSelectedAutocompleteItem();
// Delete the first entry, that is the 1nd entry of history.
synthesizeKey("KEY_ArrowUp");
deleteSelectedAutocompleteItem();
await notifyMenuChanged(3);
assertAutocompleteItems("PASS1", "PASS2", "final");
assertValueAfterKeys(input, "KEY_Enter", "Google");
});
for (const input of document
.querySelectorAll("form#show_datalist_for_text_inputs_only input")) {
const expectPopup = input.getAttribute("popup") == "true";
add_named_task(
`datalist_is_${expectPopup ? "" : "not_"}shown_for_${input.type}_input`,
async () => {
input.focus();
is(document.activeElement, input, "Input is focused.");
await (expectPopup ? popupByArrowDown() : noPopupByArrowDown());
}
);
}
</script>
</body>
</html>