summaryrefslogtreecommitdiffstats
path: root/toolkit/components/satchel/test/test_form_autocomplete_with_list.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/satchel/test/test_form_autocomplete_with_list.html')
-rw-r--r--toolkit/components/satchel/test/test_form_autocomplete_with_list.html402
1 files changed, 402 insertions, 0 deletions
diff --git a/toolkit/components/satchel/test/test_form_autocomplete_with_list.html b/toolkit/components/satchel/test/test_form_autocomplete_with_list.html
new file mode 100644
index 0000000000..b903af5246
--- /dev/null
+++ b/toolkit/components/satchel/test/test_form_autocomplete_with_list.html
@@ -0,0 +1,402 @@
+<!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>