diff options
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.html | 402 |
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> |