diff options
Diffstat (limited to 'testing/web-platform/tests/html/semantics/forms/the-form-element')
24 files changed, 1579 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-in-inactive-document-crash.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-in-inactive-document-crash.html new file mode 100644 index 0000000000..8a3543fcbc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-in-inactive-document-crash.html @@ -0,0 +1,6 @@ +<iframe id="i"></iframe> +<script> +var form = i.contentDocument.createElement("form"); +i.remove(); +form.action = "GET"; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-reflection-with-base-url.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-reflection-with-base-url.html new file mode 100644 index 0000000000..67828a3077 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-reflection-with-base-url.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>form.action with a base URL</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-fs-action"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<base href="/common/blank.html"> + +<form id="form1" action="a.html"></form> +<form id="form2" action=""></form> +<form id="form3"></form> + +<script> +"use strict"; + +test(() => { + + assert_equals(document.querySelector("#form1").action, (new URL("a.html", document.baseURI)).href, + "action should equal the correct absolute URL"); + +}, "An action URL should be resolved relative to the document's base URL (not the document's URL)"); + +test(() => { + + assert_equals(document.querySelector("#form2").action, document.URL); + +}, "An empty-string action content attribute should cause the IDL attribute to return the document's URL (not the document's base URL)"); + +test(() => { + + assert_equals(document.querySelector("#form3").action, document.URL); + +}, "A missing action content attribute should cause the IDL attribute to return the document's URL (not the document's base URL)"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-reflection.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-reflection.html new file mode 100644 index 0000000000..c92fd0f0cf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-reflection.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>form.action</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-fs-action"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<form id="form1" action="a.html"></form> +<form id="form2" action=""></form> +<form id="form3"></form> + +<script> +"use strict"; + +test(() => { + + assert_equals(document.querySelector("#form1").action, (new URL("a.html", document.baseURI)).href, + "action should equal the correct absolute URL"); + +}, "An action URL should be resolved relative to the document's base URL (= the document's URL in this case)"); + +test(() => { + + assert_equals(document.querySelector("#form2").action, document.URL); + +}, "An empty-string action content attribute should cause the IDL attribute to return the document's URL (= the document's base URL in this case)"); + +test(() => { + + assert_equals(document.querySelector("#form3").action, document.URL); + +}, "A missing action content attribute should cause the IDL attribute to return the document's URL (= the document's base URL in this case)"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-submission-with-base-url.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-submission-with-base-url.html new file mode 100644 index 0000000000..baee5500de --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-submission-with-base-url.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>form action="" attribute effect on submission</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-fs-action"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +// promise_test instead of async_test because all tests use window.success, and so can't run at the same time. + +promise_test(t => { + return new Promise(resolve => { + window.success = t.step_func(locationLoaded => { + const expected = (new URL("resources/target/form-action-url-target.html?name=value", location.href)).href; + assert_equals(locationLoaded, expected); + resolve(); + }); + + const iframe = document.createElement("iframe"); + iframe.src = "resources/form-with-action-and-base.sub.html?action=form-action-url-target.html"; + document.body.appendChild(iframe); + }); +}, "An action URL should be resolved relative to the document's base URL (not document URL)"); + +promise_test(t => { + return new Promise(resolve => { + window.success = t.step_func(locationLoaded => { + const expected = (new URL("resources/form-with-action-and-base.sub.html?name=value", location.href)).href; + assert_equals(locationLoaded, expected); + resolve(); + }); + + const iframe = document.createElement("iframe"); + iframe.src = "resources/form-with-action-and-base.sub.html?action="; + document.body.appendChild(iframe); + }); +}, "An empty-string action should submit the form to its containing document's URL (not its base URL)"); + +promise_test(t => { + return new Promise(resolve => { + window.success = t.step_func(locationLoaded => { + const expected = (new URL("resources/form-no-action-with-base.html?name=value", location.href)).href; + assert_equals(locationLoaded, expected); + resolve(); + }); + + const iframe = document.createElement("iframe"); + iframe.src = "resources/form-no-action-with-base.html"; + document.body.appendChild(iframe); + }); +}, "A missing action should submit the form to its containing document's URL (not its base URL)"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-submission.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-submission.html new file mode 100644 index 0000000000..54ca7b5ff5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action-submission.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>form action="" attribute effect on submission</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-fs-action"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +// promise_test instead of async_test because all tests use window.success, and so can't run at the same time. + +promise_test(t => { + return new Promise(resolve => { + window.success = t.step_func(locationLoaded => { + const expected = (new URL("resources/target/form-action-url-target.html?name=value", location.href)).href; + assert_equals(locationLoaded, expected); + resolve(); + }); + + const iframe = document.createElement("iframe"); + iframe.src = "resources/form-with-action.sub.html?action=target/form-action-url-target.html"; + document.body.appendChild(iframe); + }); +}, "An action URL should be resolved relative to the document's base URL (= document's URL in this case)"); + +promise_test(t => { + return new Promise(resolve => { + window.success = t.step_func(locationLoaded => { + const expected = (new URL("resources/form-with-action.sub.html?name=value", location.href)).href; + assert_equals(locationLoaded, expected); + resolve(); + }); + + const iframe = document.createElement("iframe"); + iframe.src = "resources/form-with-action.sub.html?action="; + document.body.appendChild(iframe); + }); +}, "An empty-string action should submit the form to the document's URL (= document's base URL in this case)"); + +promise_test(t => { + return new Promise(resolve => { + window.success = t.step_func(locationLoaded => { + const expected = (new URL("resources/form-no-action.html?name=value", location.href)).href; + assert_equals(locationLoaded, expected); + resolve(); + }); + + const iframe = document.createElement("iframe"); + iframe.src = "resources/form-no-action.html"; + document.body.appendChild(iframe); + }); +}, "A missing action should submit the form to the document's URL (= document's base URL in this case)"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action.html new file mode 100644 index 0000000000..14717c5e6a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-action.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>Forms</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <p> + <h3>Form_action</h3> + </p> + + <hr> + + <div id="log"></div> + + <form method="post" + enctype="application/x-www-form-urlencoded" + action="http://www.google.com/" + id="input_form"> + <p><input type=hidden name="custname"></p> + <p><input type=hidden name="custtel"></p> + <p><input type=hidden name="custemail"></p> + + </form> + <script> + + var form = document.getElementById("input_form"); + + if (typeof(form.action) == "string") { + test(function() { + assert_equals(form.action, "http://www.google.com/", "action attribute is not correct."); + }); + } else { + test(function() { + assert_unreached("action attribute is not exist."); + }); + } + + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html new file mode 100644 index 0000000000..fcd93ce2ef --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html @@ -0,0 +1,130 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>form autocomplete attribute</title> +<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org"> +<link rel=help href="https://html.spec.whatwg.org/multipage/#the-form-element"> +<link rel=help href="https://html.spec.whatwg.org/multipage/#attr-fe-autocomplete"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<form name="missing_attribute"> + <input> + <input autocomplete="on"> + <input autocomplete="off"> + <input autocomplete="foobar"> +</form> +<form name="autocomplete_on" autocomplete="on"> + <input> + <input autocomplete="on"> + <input autocomplete="off"> + <input autocomplete="foobar"> +</form> +<form name="autocomplete_off" autocomplete="off"> + <input> + <input autocomplete="on"> + <input autocomplete="off"> + <input autocomplete="foobar"> +</form> +<form name="autocomplete_invalid" autocomplete="foobar"> + <input> + <input autocomplete="on"> + <input autocomplete="off"> + <input autocomplete="foobar"> +</form> +<script> + function autocompletetest(form, expectedValues, desc) { + test(function(){ + assert_equals(form.autocomplete, expectedValues[0]); + assert_equals(form.elements[0].autocomplete, expectedValues[1]); + assert_equals(form.elements[1].autocomplete, expectedValues[2]); + assert_equals(form.elements[2].autocomplete, expectedValues[3]); + assert_equals(form.elements[3].autocomplete, expectedValues[4]); + }, desc); + } + + autocompletetest(document.forms.missing_attribute, ["on", "", "on", "off", ""], "form autocomplete attribute missing"); + autocompletetest(document.forms.autocomplete_on, ["on", "", "on", "off", ""], "form autocomplete attribute on"); + autocompletetest(document.forms.autocomplete_off, ["off", "", "on", "off", ""], "form autocomplete attribute off"); + autocompletetest(document.forms.autocomplete_invalid, ["on", "", "on", "off", ""], "form autocomplete attribute invalid"); + + var keywords = [ "on", "off", "name", "honorific-prefix", "given-name", "additional-name", "family-name", "honorific-suffix", "nickname", "username", "new-password", "current-password", "one-time-code", "organization-title", "organization", "street-address", "address-line1", "address-line2", "address-line3", "address-level4", "address-level3", "address-level2", "address-level1", "country", "country-name", "postal-code", "cc-name", "cc-given-name", "cc-additional-name", "cc-family-name", "cc-number", "cc-exp", "cc-exp-month", "cc-exp-year", "cc-csc", "cc-type", "transaction-currency", "transaction-amount", "language", "bday", "bday-day", "bday-month", "bday-year", "sex", "url", "photo", "tel", "tel-country-code", "tel-national", "tel-area-code", "tel-local", "tel-local-prefix", "tel-local-suffix", "tel-extension", "email", "impp", "webauthn" ]; + + keywords.forEach(function(keyword) { + test(function(){ + var input = document.createElement("input"); + // Include whitespace to test splitting tokens on whitespace. + // Convert to uppercase to ensure that the tokens are normalized to lowercase. + input.setAttribute("autocomplete", " " + keyword.toUpperCase() + "\t"); + assert_equals(input.autocomplete, keyword); + }, keyword + " is an allowed autocomplete field name"); + }); + + +test(() => { + const select = document.createElement("select"); + select.setAttribute("autocomplete", " \n"); + assert_equals(select.autocomplete, ""); +}, "Test whitespace-only attribute value"); + +test(() => { + const select = document.createElement("select"); + + select.setAttribute("autocomplete", "foo off"); + assert_equals(select.autocomplete, ""); + + // Normal category; max=3 + select.setAttribute("autocomplete", "foo section-foo billing name"); + assert_equals(select.autocomplete, ""); + + // Contact category; max=4 + select.setAttribute("autocomplete", "foo section-bar billing work tel"); + assert_equals(select.autocomplete, ""); + + // Credential category; max=5 + select.setAttribute("autocomplete", "foo section-bar billing work tel webauthn"); + assert_equals(select.autocomplete, ""); +}, "Test maximum number of tokens"); + +test(() => { + const textarea = document.createElement("textarea"); + + textarea.setAttribute("autocomplete", "call-sign"); + assert_equals(textarea.autocomplete, ""); +}, "Unknown field"); + +test(() => { + const hidden = document.createElement("input"); + hidden.type = "hidden"; + hidden.setAttribute("autocomplete", "on"); + assert_equals(hidden.autocomplete, ""); + hidden.setAttribute("autocomplete", "off"); + assert_equals(hidden.autocomplete, ""); +}, "Test 'wearing the autofill anchor mantle' with off/on"); + +test(() => { + const textarea = document.createElement("textarea"); + + textarea.setAttribute("autocomplete", " HOME\ntel"); + assert_equals(textarea.autocomplete, "home tel"); + + textarea.setAttribute("autocomplete", "shipping country"); + assert_equals(textarea.autocomplete, "shipping country"); + + textarea.setAttribute("autocomplete", "billing work email"); + assert_equals(textarea.autocomplete, "billing work email"); + + textarea.setAttribute("autocomplete", " section-FOO bday"); + assert_equals(textarea.autocomplete, "section-foo bday"); +}, "Serialize combinations of section, mode, contact, and field"); + +test(() => { + const textarea = document.createElement("textarea"); + + textarea.setAttribute("autocomplete", "\tusername webauthn"); + assert_equals(textarea.autocomplete, "username webauthn"); + + textarea.setAttribute("autocomplete", " section-LOGIN shipping work tel webauthn "); + assert_equals(textarea.autocomplete, "section-login shipping work tel webauthn"); +}, "Serialize combinations of section, mode, contact, field, and credential"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-checkvalidity.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-checkvalidity.html new file mode 100644 index 0000000000..941ab94d45 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-checkvalidity.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>Forms</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <p> + <h3>Form_checkValidity</h3> + </p> + + <hr> + + <div id="log"></div> + + <form method="post" + enctype="application/x-www-form-urlencoded" + action="" + id="input_form"> + <p><input type=hidden name="custname"></p> + <p><input type=hidden name="custtel"></p> + <p><input type=hidden name="custemail"></p> + + </form> + <script> + + var form = document.getElementById("input_form"); + + try + { + var ret = form.checkValidity(); + + test(function() { + assert_equals(ret, true, "calling of checkValidity method is failed."); + }); + } + catch (e) { + test(function() { + assert_unreached("Error is raised."); + }); + } + + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-filter.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-filter.html new file mode 100644 index 0000000000..693560188a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-filter.html @@ -0,0 +1,192 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>form.elements must contain all listed elements with the form owner</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-form-elements"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> + +<!-- + Elements with data-in are expected to be in the form.elements collection. + The choice of other elements besides "listed elements" (i.e. img, label, meter, progress) was + because those are ones that appear in form-associated or labelable element categories. +--> + +<button data-in form="form" id="before-button1"></button> +<fieldset data-in form="form" id="before-fieldset1"></fieldset> +<object data-in form="form" id="before-object1"></object> +<output data-in form="form" id="before-output1"></output> +<select data-in form="form" id="before-select1"> + <option form="form" id="before-option1">x</option> +</select> +<textarea data-in form="form" id="before-textarea1"></textarea> + +<input data-in form="form" id="before-input1"> +<input data-in type="hidden" form="form" id="before-input2"> +<input data-in type="search" form="form" id="before-input3"> +<input data-in type="tel" form="form" id="before-input4"> +<input data-in type="url" form="form" id="before-input5"> +<input data-in type="email" form="form" id="before-input6"> +<input data-in type="password" form="form" id="before-input7"> +<input data-in type="date" form="form" id="before-input8"> +<input data-in type="month" form="form" id="before-input9"> +<input data-in type="week" form="form" id="before-input10"> +<input data-in type="time" form="form" id="before-input11"> +<input data-in type="datetime-local" form="form" id="before-input12"> +<input data-in type="number" form="form" id="before-input13"> +<input data-in type="range" form="form" id="before-input14"> +<input data-in type="color" form="form" id="before-input15"> +<input data-in type="checkbox" form="form" id="before-input16"> +<input data-in type="radio" form="form" id="before-input17"> +<input data-in type="file" form="form" id="before-input18"> +<input data-in type="submit" form="form" id="before-input19"> +<input data-in type="reset" form="form" id="before-input20"> +<input data-in type="button" form="form" id="before-input21"> + +<img form="form" id="before-img1"> +<label form="form" id="before-label1"></label> +<meter form="form" id="before-meter1"></meter> +<progress form="form" id="before-progress1"></progress> + +<form id="form"> + <button data-in id="button1"></button> + <fieldset data-in id="fieldset1"></fieldset> + <object data-in id="object1"></object> + <output data-in id="output1"></output> + <select data-in id="select1"> + <option id="option1">x</option> + </select> + <textarea data-in id="textarea1"></textarea> + + <input data-in id="input1"> + <input data-in type="hidden" id="input2"> + <input data-in type="search" id="input3"> + <input data-in type="tel" id="input4"> + <input data-in type="url" id="input5"> + <input data-in type="email" id="input6"> + <input data-in type="password" id="input7"> + <input data-in type="date" id="input8"> + <input data-in type="month" id="input9"> + <input data-in type="week" id="input10"> + <input data-in type="time" id="input11"> + <input data-in type="datetime-local" id="input12"> + <input data-in type="number" id="input13"> + <input data-in type="range" id="input14"> + <input data-in type="color" id="input15"> + <input data-in type="checkbox" id="input16"> + <input data-in type="radio" id="input17"> + <input data-in type="file" id="input18"> + <input data-in type="submit" id="input19"> + <input data-in type="reset" id="input20"> + <input data-in type="button" id="input21"> + + <img id="img1"> + <label id="label1"></label> + <meter id="meter1"></meter> + <progress id="progress1"></progress> +</form> + +<button data-in form="form" id="after-button1"></button> +<fieldset data-in form="form" id="after-fieldset1"></fieldset> +<object data-in form="form" id="after-object1"></object> +<output data-in form="form" id="after-output1"></output> +<select data-in form="form" id="after-select1"> + <option form="form" id="after-option1">x</option> +</select> +<textarea data-in form="form" id="after-textarea1"></textarea> + +<input data-in form="form" id="after-input1"> +<input data-in type="hidden" form="form" id="after-input2"> +<input data-in type="search" form="form" id="after-input3"> +<input data-in type="tel" form="form" id="after-input4"> +<input data-in type="url" form="form" id="after-input5"> +<input data-in type="email" form="form" id="after-input6"> +<input data-in type="password" form="form" id="after-input7"> +<input data-in type="date" form="form" id="after-input8"> +<input data-in type="month" form="form" id="after-input9"> +<input data-in type="week" form="form" id="after-input10"> +<input data-in type="time" form="form" id="after-input11"> +<input data-in type="datetime-local" form="form" id="after-input12"> +<input data-in type="number" form="form" id="after-input13"> +<input data-in type="range" form="form" id="after-input14"> +<input data-in type="color" form="form" id="after-input15"> +<input data-in type="checkbox" form="form" id="after-input16"> +<input data-in type="radio" form="form" id="after-input17"> +<input data-in type="file" form="form" id="after-input18"> +<input data-in type="submit" form="form" id="after-input19"> +<input data-in type="reset" form="form" id="after-input20"> +<input data-in type="button" form="form" id="after-input21"> + +<img form="form" id="after-img1"> +<label form="form" id="after-label1"></label> +<meter form="form" id="after-meter1"></meter> +<progress form="form" id="after-progress1"></progress> + +<button id="after-unassociated-button1"></button> +<fieldset id="after-unassociated-fieldset1"></fieldset> +<object id="after-unassociated-object1"></object> +<output id="after-unassociated-output1"></output> +<select id="after-unassociated-select1"> + <option id="after-unassociated-option1">x</option> +</select> +<textarea id="after-unassociated-textarea1"></textarea> + +<input id="after-unassociated-input1"> +<input type="hidden" id="after-unassociated-input2"> +<input type="search" id="after-unassociated-input3"> +<input type="tel" id="after-unassociated-input4"> +<input type="url" id="after-unassociated-input5"> +<input type="email" id="after-unassociated-input6"> +<input type="password" id="after-unassociated-input7"> +<input type="date" id="after-unassociated-input8"> +<input type="month" id="after-unassociated-input9"> +<input type="week" id="after-unassociated-input10"> +<input type="time" id="after-unassociated-input11"> +<input type="datetime-local" id="after-unassociated-input12"> +<input type="number" id="after-unassociated-input13"> +<input type="range" id="after-unassociated-input14"> +<input type="color" id="after-unassociated-input15"> +<input type="checkbox" id="after-unassociated-input16"> +<input type="radio" id="after-unassociated-input17"> +<input type="file" id="after-unassociated-input18"> +<input type="submit" id="after-unassociated-input19"> +<input type="reset" id="after-unassociated-input20"> +<input type="button" id="after-unassociated-input21"> + +<img id="after-unassociated-img1"> +<label id="after-unassociated-label1"></label> +<meter id="after-unassociated-meter1"></meter> +<progress id="after-unassociated-progress1"></progress> + +<form id="form2"> + <span id="shadow-1"></span> +</form> +<span id="shadow-2"></span> + +<script> +"use strict"; +test(() => { + const elements = document.querySelector("#form").elements; + const ids = Array.from(elements).map(el => el.id); + + const allCorrectIDs = Array.from(document.querySelectorAll("[data-in]")).map(el => el.id); + + assert_array_equals(ids, allCorrectIDs); +}); + +test(() => { + const shadowRoot1 = document.querySelector("#shadow-1").attachShadow({mode: "open"}); + const input1 = document.createElement("input"); + shadowRoot1.appendChild(input1); + + const shadowRoot2 = document.querySelector("#shadow-2").attachShadow({mode: "open"}); + const input2 = document.createElement("input"); + input2.setAttribute("form", "form2"); + shadowRoot2.appendChild(input2); + + assert_equals(document.querySelector("#form2").elements.length, 0); + assert_equals(input1.form, null); + assert_equals(input2.form, null); +}, "form.elements only includes elements from the same shadow tree"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-interfaces-01.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-interfaces-01.html new file mode 100644 index 0000000000..c8b4a6c71e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-interfaces-01.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>form.elements: interfaces</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-form-elements"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#htmlformcontrolscollection"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var form = document.createElement("form"); + ["HTMLFormControlsCollection", "HTMLCollection"].forEach(function(i) { + test(function() { + assert_true(i in window, "Interface should exist") + assert_true(form.elements instanceof window[i], + "elements should implement the interface") + }, "Testing interface " + i) + }) +}) +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-matches.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-matches.html new file mode 100644 index 0000000000..7921627265 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-matches.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<title>form.elements: matches</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-form-elements"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div id="test"> +<form id="form"> +<input type="image"> +</form> +</div> +<script> +test(function() { + assert_equals(document.getElementById("form").elements.length, 0); +}, "input type=image should not be present in the form.elements collection") +test(function() { + var form = document.getElementById("form"); + var i = document.createElement("input"); + i.name = "2"; + form.appendChild(i); + var j = document.createElement("input"); + j.name = "03"; + form.appendChild(j); + assert_equals(form.elements[-1], undefined, '[-1]'); + assert_equals(form.elements["-1"], undefined, '["-1"]'); + assert_equals(form.elements[0], i, '[0]'); + assert_equals(form.elements["0"], i, '["0"]'); + assert_equals(form.elements[1], j, '[1]'); + assert_equals(form.elements["1"], j, '["1"]'); + assert_equals(form.elements[2], undefined, '[2]'); + assert_equals(form.elements["2"], undefined, '["2"]'); + assert_equals(form.elements[03], undefined, '[03]'); + assert_equals(form.elements["03"], j, '["03"]'); + assert_equals(form.elements.item(-1), null, 'item(-1)'); + assert_equals(form.elements.item(0), i, 'item(0)'); + assert_equals(form.elements.item(1), j, 'item(1)'); + assert_equals(form.elements.item(2), null, 'item(2)'); + assert_equals(form.elements.namedItem("2"), i, 'namedItem("2")'); + assert_equals(form.elements.namedItem("03"), j, 'namedItem("03")'); + assert_equals(form.elements.namedItem("3"), null, 'namedItem("3")'); + assert_array_equals(form.elements, [i, j]); + form.removeChild(i); + form.removeChild(j); +}, "form.elements should include elements whose name starts with a number"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-nameditem-01.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-nameditem-01.html new file mode 100644 index 0000000000..0b5aeb8ef5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-nameditem-01.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<title>form.elements: namedItem</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-form-elements"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div id="test"> +<form id=form> +<input name=b id=i1> +<input name=b id=i2> +</form> +</div> +<script> +test(function() { + assert_true("RadioNodeList" in window, "RadioNodeList should exist"); +}, "RadioNodeList should exist") +test(function() { + var nl = document.forms.form.elements["b"]; + assert_true(nl instanceof NodeList, "Should get a NodeList"); + if ("RadioNodeList" in window) { + assert_true(nl instanceof RadioNodeList, "Should get a RadioNodeList"); + } + assert_array_equals(nl, + [document.getElementById("i1"), + document.getElementById("i2")]); + + var el = nl[0]; + el.parentNode.removeChild(el); + assert_true(nl instanceof NodeList, "Should get a NodeList"); + if ("RadioNodeList" in window) { + assert_true(nl instanceof RadioNodeList, "Should get a RadioNodeList"); + } + assert_array_equals(nl, [document.getElementById("i2")]); + assert_equals(document.forms.form.elements["b"], document.getElementById("i2")); +}, "elements collection should return elements or RadioNodeLists") +test(function() { + var fs = document.forms.form.appendChild(document.createElement("fieldset")); + fs.name = "fs"; + assert_equals(document.forms.form.elements.fs, fs); + fs.parentNode.removeChild(fs); +}, "elements collection should include fieldsets") +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-nameditem-02.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-nameditem-02.html new file mode 100644 index 0000000000..c25e554de1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-nameditem-02.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>form.elements: parsing</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-form-elements"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#parsing-main-intr"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div id="test"> +<form id=form> +<table> +<tr> +<td><input type="radio" name="radio1" id="r1" value=1></td> +<td><input type="radio" name="radio2" id="r2" value=2></td> +<input type="radio" name="radio0" id="r0" value=0> +</tr> +</table> +</form> +</div> +<script> +test(function() { + var form = document.getElementById("form"); + assert_array_equals(form.elements, + [document.getElementById("r0"), + document.getElementById("r1"), + document.getElementById("r2")]); +}, "form.elements should work correctly in the face of table syntax errors") +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-sameobject.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-sameobject.html new file mode 100644 index 0000000000..1c1aa5d3dd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-elements-sameobject.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Testing [SameObject] on the 'elements' attribute on the 'form' element</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> + +<form> + <input> +</form> + +<script> +test(function() { + var form = document.querySelector('form'); + var elements = form.elements; + assert_equals(elements, form.elements); + form.appendChild(document.createElement('input')); + assert_equals(elements, form.elements); +}, "[SameObject] should apply to 'elements' attr on <form>"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-indexed-element-shadow.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-indexed-element-shadow.html new file mode 100644 index 0000000000..a108ce8a93 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-indexed-element-shadow.html @@ -0,0 +1,26 @@ +<!doctype html> +<meta charset="utf-8"> +<title>form.elements: indexed access reflects DOM order, not flat tree</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<form id="target"> + <div id="host"> + <template shadowrootmode="open"> + <slot name="first"></slot> + <slot name="second"></slot> + </template> + <input id="first" slot="second"> + <input id="second" slot="first"> + </div> +</form> +<script> +test(function() { + let target = document.getElementById("target"); + let host = document.getElementById("host"); + assert_true(!!host.shadowRoot, "Should have a shadow tree"); + assert_equals(target.elements[0], first, "form.elements reflects DOM order, not flat tree order"); + assert_equals(target.elements[1], second); +}); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-indexed-element.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-indexed-element.html new file mode 100644 index 0000000000..5ea96d3d1b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-indexed-element.html @@ -0,0 +1,45 @@ +<!doctype html> +<meta charset="utf-8"> +<title>form.elements: indexed</title> +<link rel="author" title="Ivan.Yang" href="mailto:jsyangwenjie@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div id="test"> +<form id=form> +<input type="radio" name="radio1" id="r1" value=1> +<input type="radio" name="radio2" id="r2" value=2> +</form> +</div> +<script> +test(function() { + var form = document.getElementById("form"); + assert_equals(form[0], document.getElementById("r1")); + assert_equals(form[1], document.getElementById("r2")); + assert_equals(form[2], undefined); + assert_equals(form[-1], undefined); +}, "form.elements should be accessed correctly by index") + +test(function(){ + var form = document.getElementById("form"); + var old_item = form[0]; + var old_desc = Object.getOwnPropertyDescriptor(form, 0); + assert_equals(old_desc.value, old_item); + assert_true(old_desc.enumerable); + assert_true(old_desc.configurable); + assert_false(old_desc.writable); + + Object.prototype[0] = 5; + this.add_cleanup(function () { delete Object.prototype[0]; }); + assert_equals(form[0], old_item); + + delete form[0]; + assert_equals(form[0], old_item); + + assert_throws_js(TypeError, function() { + "use strict"; + delete form[0]; + }); + assert_equals(form[0], old_item); +}, 'Trying to delete an indexed property name should never work'); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-length.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-length.html new file mode 100644 index 0000000000..3326809fc6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-length.html @@ -0,0 +1,38 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>Forms</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <p> + <h3>Form_length</h3> + </p> + + <hr> + + <div id="log"></div> + + <form method="post" + enctype="application/x-www-form-urlencoded" + action="" + id="input_form"> + <p><input type=hidden name="custname"></p> + <p><input type=hidden name="custtel"></p> + <p><input type=hidden name="custemail"></p> + + </form> + <script> + + var form = document.getElementById("input_form"); + var len = form.length; + + test(function() { + assert_equals(len, 3, "length attribute is not correct."); + }); + + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html new file mode 100644 index 0000000000..7b7d573615 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html @@ -0,0 +1,418 @@ +<!doctype html> +<meta charset=utf-8> +<title>Form named getter</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<!-- XXX Nothing tests id attributes yet. --> +<!-- XXX We also need tests for moving inputs and forms in the DOM. --> +<form> +<input type=button name=button> +<input type=radio name=radio value=x> +<input type=radio name=radio value=y> +<input type=radio name=radio value=z> +</form> + +<form> +<button name=l1></button> +<fieldset name=l2></fieldset> +<input type=hidden name=l3> +<input type=text name=l4> +<input type=search name=l5> +<input type=tel name=l6> +<input type=url name=l7> +<input type=email name=l8> +<input type=password name=l9> +<input type=datetime name=l10> +<input type=date name=l11> +<input type=month name=l12> +<input type=week name=l13> +<input type=time name=l14> +<input type=datetime-local name=l15> +<input type=number name=l16> +<input type=range name=l17> +<input type=color name=l18> +<input type=checkbox name=l19> +<input type=radio name=l20> +<input type=file name=l21> +<input type=submit name=l22> +<input type=image name=l23> +<input type=reset name=l24> +<input type=button name=l25> +<input type=foo name=l26> +<input name=l27> +<object name=l28></object> +<output name=l29></output> +<select name=l30></select> +<textarea name=l31></textarea> +</form> + +<form> +<!-- EventTarget --> +<input type=radio name=addEventListener> +<input type=radio name=removeEventListener> +<input type=radio name=dispatchEvent> + +<!-- Node --> +<input type=radio name=nodeType> +<input type=radio name=nodeName> +<input type=radio name=ownerDocument> + +<!-- Element --> +<input type=radio name=namespaceURI> +<input type=radio name=prefix> +<input type=radio name=localName> + +<!-- HTMLElement --> +<input type=radio name=title> +<input type=radio name=lang> +<input type=radio name=dir> + +<!-- HTMLFormElement --> +<input type=radio name=acceptCharset> +<input type=radio name=action> +<input type=radio name=autocomplete> +<input type=radio name=enctype> +<input type=radio name=encoding> +<input type=radio name=method> +<input type=radio name=name> +<input type=radio name=noValidate> +<input type=radio name=target> +<input type=radio name=elements> +<input type=radio name=length> +<input type=radio name=submit> +<input type=radio name=reset> +<input type=radio name=checkValidity> +</form> + +<img name=x> +<form></form><!-- no child nodes --> +<img name=y> +<form><!-- a child node --></form> +<img name=z> + +<input form=a name=b> +<form id=a></form> +<input form=c name=d> +<input form=c name=d> +<form id=c></form> +<script> +test(function() { + var form = document.getElementsByTagName("form")[0] + assert_equals(form.item, undefined) + assert_false("item" in form) +}, "Forms should not have an item method") + +test(function() { + var form = document.getElementsByTagName("form")[0] + assert_equals(form.namedItem, undefined) + assert_false("namedItem" in form) +}, "Forms should not have a namedItem method") + +test(function() { + var form = document.getElementsByTagName("form")[0] + var button = document.getElementsByTagName("input")[0] + assert_equals(button.type, "button") + assert_equals(form.button, button) + var desc = Object.getOwnPropertyDescriptor(form, "button"); + assert_equals(desc.value, button); + assert_false(desc.writable); + assert_true(desc.configurable); + assert_false(desc.enumerable); + assert_equals(form.button.length, undefined) +}, "Name for a single element should work") + +test(function() { + var form = document.getElementsByTagName("form")[0] + assert_equals(form.radio.item(-1), null) + assert_array_equals([0, 1, 2].map(function(i) { + return form.radio.item(i).value + }), ["x", "y", "z"]) + assert_equals(form.radio.item(3), null) +}, "Calling item() on the NodeList returned from the named getter should work") + +test(function() { + var form = document.getElementsByTagName("form")[0] + assert_equals(form.radio.length, 3) + assert_equals(form.radio[-1], undefined) + assert_array_equals([0, 1, 2].map(function(i) { + return form.radio[i].value + }), ["x", "y", "z"]) + assert_equals(form.radio[3], undefined) +}, "Indexed getter on the NodeList returned from the named getter should work") + +test(function() { + var form = document.getElementsByTagName("form")[0] + var indices = [-1, 0, 1, 2, 3] + indices.forEach(function(i) { + assert_throws_js(TypeError, function() { + form.radio(i) + }) + }) +}, "Invoking a legacycaller on the NodeList returned from the named getter " + + "should not work") + +test(function() { + var form = document.getElementsByTagName("form")[1] + for (var i = 1; i <= 31; ++i) { + if (i == 23) { + // input type=image + assert_equals(form["l" + i], undefined) + } else { + assert_equals(form["l" + i], form.children[i - 1]) + } + } +}, "All listed elements except input type=image should be present in the form") + +test(function() { + var names = [ + // EventTarget + "addEventListener", "removeEventListener", "dispatchEvent", + // Node + "nodeType", "nodeName", "ownerDocument", + // Element + "namespaceURI", "prefix", "localName", + // HTMLElement + "title", "lang", "dir", + // HTMLFormElement + "acceptCharset", "action", "autocomplete", "enctype", "encoding", "method", + "name", "noValidate", "target", "elements", "length", "submit", "reset", + "checkValidity" + ] + var form = document.getElementsByTagName("form")[2] + names.forEach(function(name, i) { + assert_equals(form[name], form.children[i]) + }) +}, "Named elements should override builtins") + +test(function() { + var form = document.getElementsByTagName("form")[3] + assert_equals(form.x, undefined, "x should not be associated with the form") + assert_equals(form.y, undefined, "y should not be associated with the form") + assert_equals(form.z, undefined, "z should not be associated with the form") + assert_equals(form[0], undefined, "The form should not have supported property indices") + assert_equals(form.length, 0) +}, "Named items outside the form should not be returned (no children)") + +test(function() { + var form = document.getElementsByTagName("form")[4] + assert_equals(form.x, undefined, "x should not be associated with the form") + assert_equals(form.y, undefined, "y should not be associated with the form") + assert_equals(form.z, undefined, "z should not be associated with the form") + assert_equals(form[0], undefined, "The form should not have supported property indices") + assert_equals(form.length, 0) +}, "Named items outside the form should not be returned (one child)") + +test(function() { + var form = document.getElementsByTagName("form")[5] + assert_equals(form.id, "a") + + var input = document.getElementsByName("b")[0] + assert_equals(input.localName, "input") + assert_equals(input.getAttribute("form"), "a") + + assert_equals(form.b, input); +}, "The form attribute should be taken into account for named getters (single element)") + +test(function() { + var form = document.getElementsByTagName("form")[6] + assert_equals(form.id, "c") + + var input1 = document.getElementsByName("d")[0] + assert_equals(input1.localName, "input") + assert_equals(input1.getAttribute("form"), "c") + + var input2 = document.getElementsByName("d")[1] + assert_equals(input2.localName, "input") + assert_equals(input2.getAttribute("form"), "c") + + var desc = Object.getOwnPropertyDescriptor(form, "d"); + assert_equals(desc.value, form.d); + assert_false(desc.writable); + assert_true(desc.configurable); + assert_false(desc.enumerable); + + assert_true(form.d instanceof NodeList, "form.d should be a NodeList") + assert_array_equals(form.d, [input1, input2]) +}, "The form attribute should be taken into account for named getters (multiple elements)") + +test(function() { + var f = document.body.appendChild(document.createElement("form")) + f.id = "f" + var g = f.appendChild(document.createElement("form")) + g.id = "g" + var input = g.appendChild(document.createElement("input")) + input.name = "x" + assert_equals(f.x, undefined) + assert_equals(g.x, input) +}, "Input should only be a named property on the innermost form that contains it") + +test(function() { + var form = document.getElementsByTagName("form")[1]; + var old_item = form["l1"]; + var old_desc = Object.getOwnPropertyDescriptor(form, "l1"); + assert_equals(old_desc.value, old_item); + assert_false(old_desc.enumerable); + assert_true(old_desc.configurable); + assert_false(old_desc.writable); + + form["l1"] = 5; + assert_equals(form["l1"], old_item); + assert_throws_js(TypeError, function() { + "use strict"; + form["l1"] = 5; + }); + assert_throws_js(TypeError, function() { + Object.defineProperty(form, "l1", { value: 5 }); + }); + + delete form["l1"]; + assert_equals(form["l1"], old_item); + + assert_throws_js(TypeError, function() { + "use strict"; + delete form["l1"]; + }); + assert_equals(form["l1"], old_item); + +}, 'Trying to set an expando that would shadow an already-existing named property'); + +test(function() { + var form = document.getElementsByTagName("form")[1]; + var old_item = form["new-name"]; + var old_desc = Object.getOwnPropertyDescriptor(form, "new-name"); + assert_equals(old_item, undefined); + assert_equals(old_desc, undefined); + + form["new-name"] = 5; + assert_equals(form["new-name"], 5); + + var input = document.createElement("input"); + this.add_cleanup(function () {input.remove();}); + input.name = "new-name"; + form.appendChild(input); + + assert_equals(form["new-name"], 5); + + delete form["new-name"]; + assert_equals(form["new-name"], input); +}, 'Trying to set an expando that shadows a named property that gets added later'); + +test(function() { + var form = document.getElementsByTagName("form")[1]; + var old_item = form["new-name2"]; + var old_desc = Object.getOwnPropertyDescriptor(form, "new-name2"); + assert_equals(old_item, undefined); + assert_equals(old_desc, undefined); + + Object.defineProperty(form, "new-name2", { configurable: false, writable: + false, value: 5 }); + assert_equals(form["new-name2"], 5); + + var input = document.createElement("input"); + this.add_cleanup(function () {input.remove();}); + input.name = "new-name2"; + form.appendChild(input); + + assert_equals(form["new-name2"], 5); + + delete form["new-name2"]; + assert_equals(form["new-name2"], 5); + + assert_throws_js(TypeError, function() { + "use strict"; + delete form["new-name2"]; + }); + assert_equals(form["new-name2"], 5); +}, 'Trying to set a non-configurable expando that shadows a named property that gets added later'); + +test(function() { + var form = document.getElementsByTagName("form")[1]; + + var i1 = document.createElement("input"); + i1.name = "past-name1"; + i1.id = "past-id1" + + assert_equals(form["past-name1"], undefined); + assert_equals(form["past-id1"], undefined); + form.appendChild(i1); + assert_equals(form["past-name1"], i1); + assert_equals(form["past-id1"], i1); + + i1.name = "twiddled-name1"; + i1.id = "twiddled-id1"; + assert_equals(form["past-name1"], i1); + assert_equals(form["twiddled-name1"], i1); + assert_equals(form["past-id1"], i1); + assert_equals(form["twiddled-id1"], i1); + + i1.name = "twiddled-name2"; + i1.id = "twiddled-id2"; + assert_equals(form["past-name1"], i1); + assert_equals(form["twiddled-name1"], i1); + assert_equals(form["twiddled-name2"], i1); + assert_equals(form["past-id1"], i1); + assert_equals(form["twiddled-id1"], i1); + assert_equals(form["twiddled-id2"], i1); + + i1.removeAttribute("id"); + i1.removeAttribute("name"); + assert_equals(form["past-name1"], i1); + assert_equals(form["twiddled-name1"], i1); + assert_equals(form["twiddled-name2"], i1); + assert_equals(form["past-id1"], i1); + assert_equals(form["twiddled-id1"], i1); + assert_equals(form["twiddled-id2"], i1); + + i1.remove(); + assert_equals(form["past-name1"], undefined); + assert_equals(form["twiddled-name1"], undefined); + assert_equals(form["twiddled-name2"], undefined); + assert_equals(form["past-id1"], undefined); + assert_equals(form["twiddled-id1"], undefined); + assert_equals(form["twiddled-id2"], undefined); + + var i2 = document.createElement("input"); + i2.name = "past-name2"; + i2.id = "past-id2"; + + assert_equals(form["past-name2"], undefined); + assert_equals(form["past-id2"], undefined); + form.appendChild(i2); + assert_equals(form["past-name2"], i2); + assert_equals(form["past-id2"], i2); + + i2.name = "twiddled-name3"; + i2.id = "twiddled-id3"; + assert_equals(form["past-name2"], i2); + assert_equals(form["twiddled-name3"], i2); + assert_equals(form["past-id2"], i2); + assert_equals(form["twiddled-id3"], i2); + + i2.name = "twiddled-name4"; + i2.id = "twiddled-id4"; + assert_equals(form["past-name2"], i2); + assert_equals(form["twiddled-name3"], i2); + assert_equals(form["twiddled-name4"], i2); + assert_equals(form["past-id2"], i2); + assert_equals(form["twiddled-id3"], i2); + assert_equals(form["twiddled-id4"], i2); + + i2.removeAttribute("id"); + i2.removeAttribute("name"); + assert_equals(form["past-name2"], i2); + assert_equals(form["twiddled-name3"], i2); + assert_equals(form["twiddled-name4"], i2); + assert_equals(form["past-id2"], i2); + assert_equals(form["twiddled-id3"], i2); + assert_equals(form["twiddled-id4"], i2); + + i2.setAttribute("form", "c"); + assert_equals(form["past-name2"], undefined); + assert_equals(form["twiddled-name3"], undefined); + assert_equals(form["twiddled-name4"], undefined); + assert_equals(form["past-id2"], undefined); + assert_equals(form["twiddled-id3"], undefined); + assert_equals(form["twiddled-id4"], undefined); +}, "Past names map should work correctly"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-requestsubmit.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-requestsubmit.html new file mode 100644 index 0000000000..cbc46cc7d3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-requestsubmit.html @@ -0,0 +1,215 @@ +<!DOCTYPE html> +<title>form.requestSubmit() tests</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe name="iframe" src="about:blank"></iframe> + +<script> +test(() => { + document.body.insertAdjacentHTML('afterbegin', '<form>' + + '<input type="reset">' + + '<input type="text">' + + '<button type="reset"></button>' + + '<button type="button"></button>' + + '</form>'); + let form = document.querySelector('form'); + assert_throws_js(TypeError, () => { + form.requestSubmit(document.body); + }); + for (let control of form.elements) { + assert_throws_js(TypeError, () => { form.requestSubmit(control); }); + } +}, 'Passing an element which is not a submit button should throw'); + +test(() => { + document.body.insertAdjacentHTML('afterbegin', `<form> + <input form="" type="submit"> + <button form="form2" type="submit"></button> + </form> + <form id="form2"></form>`); + let form = document.querySelector('form'); + let submitButton = document.createElement('button'); + submitButton.type = 'submit'; + assert_throws_dom('NotFoundError', () => { + form.requestSubmit(submitButton); + }); + + let buttons = form.querySelectorAll('input, button'); + assert_equals(buttons.length, 2); + for (let control of buttons) { + assert_throws_dom('NotFoundError', () => { form.requestSubmit(control) }, + control.outerHTML); + } +}, 'Passing a submit button not owned by the context object should throw'); + +test(() => { + document.body.insertAdjacentHTML('afterbegin', `<input type=submit form="form1"> + <form id="form1" target="_blank"> + <button type="submit"></button> + <button></button> + <button type="invalid"></button> + <input type="submit"> + <input type="image"> + </form>`); + let form = document.querySelector('form'); + let didDispatchSubmit = false; + form.addEventListener('submit', event => { event.preventDefault(); didDispatchSubmit = true; }); + + assert_equals(form.elements.length, 5); + for (let control of form.elements) { + didDispatchSubmit = false; + form.requestSubmit(control); + assert_true(didDispatchSubmit, `${control.outerHTML} should submit the form`); + } + // <input type=image> is not in form.elements. + let control = form.querySelector('[type=image]'); + didDispatchSubmit = false; + form.requestSubmit(control); + assert_true(didDispatchSubmit, `${control.outerHTML} should submit the form`); +}, 'requestSubmit() should accept button[type=submit], input[type=submit], and input[type=image]'); + +test(() => { + document.body.insertAdjacentHTML('afterbegin', '<form><input required></form>'); + let form = document.querySelector('form'); + let invalidControl = form.querySelector('input:invalid'); + let didDispatchInvalid = false; + invalidControl.addEventListener('invalid', e => { didDispatchInvalid = true; }); + + form.requestSubmit(); + assert_true(didDispatchInvalid); +}, 'requestSubmit() should trigger interactive form validation'); + +test(() => { + document.body.insertAdjacentHTML('afterbegin', + '<form><input type=submit></form>'); + let form = document.querySelector('form'); + let submitButton = form.elements[0]; + let submitCounter = 0; + form.addEventListener('submit', e => { + ++submitCounter; + form.requestSubmit(); + e.preventDefault(); + }, {once: true}); + form.requestSubmit(); + assert_equals(submitCounter, 1, 'requestSubmit() + requestSubmit()'); + + submitCounter = 0; + form.addEventListener('submit', e => { + ++submitCounter; + submitButton.click(); + e.preventDefault(); + }, {once: true}); + form.requestSubmit(); + assert_equals(submitCounter, 1, 'requestSubmit() + click()'); + + submitCounter = 0; + form.addEventListener('submit', e => { + ++submitCounter; + form.requestSubmit(); + e.preventDefault(); + }, {once: true}); + submitButton.click(); + assert_equals(submitCounter, 1, 'click() + requestSubmit()'); +}, 'requestSubmit() doesn\'t run form submission reentrantly'); + +test(() => { + document.body.insertAdjacentHTML('afterbegin', + '<form><input type=submit><input required></form>'); + let form = document.querySelector('form'); + let submitButton = form.elements[0]; + let invalidControl = form.elements[1]; + let invalidCounter = 0; + invalidControl.addEventListener('invalid', e => { + ++invalidCounter; + if (invalidCounter < 10) + form.requestSubmit(); + }, {once: true}); + form.requestSubmit(); + assert_equals(invalidCounter, 1, 'requestSubmit() + requestSubmit()'); + + invalidCounter = 0; + invalidControl.addEventListener('invalid', e => { + ++invalidCounter; + if (invalidCounter < 10) + submitButton.click(); + }, {once: true}); + form.requestSubmit(); + assert_equals(invalidCounter, 1, 'requestSubmit() + click()'); + + invalidCounter = 0; + invalidControl.addEventListener('invalid', e => { + ++invalidCounter; + if (invalidCounter < 10) + form.requestSubmit(); + }, {once: true}); + submitButton.click(); + assert_equals(invalidCounter, 1, 'click() + requestSubmit()'); +}, 'requestSubmit() doesn\'t run interactive validation reentrantly'); + +test(() => { + let form = document.createElement('form'); + let submitCounter = 0; + form.addEventListener('submit', e => { ++submitCounter; e.preventDefault(); }); + form.requestSubmit(); + assert_equals(submitCounter, 0); +}, 'requestSubmit() for a disconnected form should not submit the form'); + +async_test(t => { + window.addEventListener('load', t.step_func(() => { + document.body.insertAdjacentHTML('afterbegin', ` +<form action="/common/blank.html"> +<input required> +<input type=submit formnovalidate formtarget=iframe name=s value=v> +</form>`); + let form = document.body.querySelector('form'); + let iframe = document.body.querySelector('iframe'); + assert_true(form.matches(':invalid'), 'The form is invalid.'); + // The form should be submitted though it is invalid. + iframe.addEventListener('load', t.step_func_done(() => { + assert_not_equals(iframe.contentWindow.location.search.indexOf('s=v'), -1); + })); + form.requestSubmit(form.querySelector('[type=submit]')); + })); +}, 'The value of the submitter should be appended, and form* ' + + 'attributes of the submitter should be handled.'); + +test(() => { + document.body.insertAdjacentHTML('afterbegin', `<form> + <input name="n1" value="v1"> + <button type="submit" name="n2" value="v2"></button> + </form> + <form id="form2"></form>`); + let form = document.querySelector('form'); + let formDataInEvent = null; + let submitter = form.querySelector('button[type=submit]'); + form.addEventListener('submit', e => { + e.preventDefault(); + formDataInEvent = new FormData(e.target); + }); + + form.requestSubmit(submitter); + assert_equals(formDataInEvent.get('n1'), 'v1'); + assert_false(formDataInEvent.has('n2')); +}, 'The constructed FormData object should not contain an entry for the submit button that was used to submit the form.'); + +async_test(t => { + document.body.insertAdjacentHTML('afterbegin', `<form> + <button type="submit" name="n1" value="v1" disabled=""></button> + </form>`); + let form = document.querySelector('form'); + let formDataInEvent = null; + let submitter = form.querySelector('button[type=submit]'); + + form.addEventListener("submit", t.step_func_done(ev => { + ev.preventDefault(); + formDataInEvent = new FormData(ev.target); + assert_false(formDataInEvent.has('n1')); + assert_equals(ev.target, form); + })); + + form.requestSubmit(submitter); + +}, "Using requestSubmit on a disabled button (via disabled attribute) should trigger submit but not be visible in FormData"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-no-action-with-base.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-no-action-with-base.html new file mode 100644 index 0000000000..b3599a45e6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-no-action-with-base.html @@ -0,0 +1,19 @@ +<!doctype html> +<base href="target/"></base> + +<form> + <input type="text" name="name" value="value"> + <input type="submit" value="Submit"> +</form> + +<script> +"use strict"; + +if (window.location.search.startsWith("?name=value")) { + // The action pointed to ourself, so the form submitted something + window.parent.success(window.location.href); +} else { + const form = document.querySelector("form"); + form.submit(); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-no-action.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-no-action.html new file mode 100644 index 0000000000..c0c2ad0330 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-no-action.html @@ -0,0 +1,18 @@ +<!doctype html> + +<form> + <input type="text" name="name" value="value"> + <input type="submit" value="Submit"> +</form> + +<script> +"use strict"; + +if (window.location.search.startsWith("?name=value")) { + // The action pointed to ourself, so the form submitted something + window.parent.success(window.location.href); +} else { + const form = document.querySelector("form"); + form.submit(); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-with-action-and-base.sub.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-with-action-and-base.sub.html new file mode 100644 index 0000000000..edb101bece --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-with-action-and-base.sub.html @@ -0,0 +1,19 @@ +<!doctype html> +<base href="target/"></base> + +<form action="{{GET[action]}}"> + <input type="text" name="name" value="value"> + <input type="submit" value="Submit"> +</form> + +<script> +"use strict"; + +if (window.location.search.startsWith("?name=value")) { + // The action pointed to ourself, so the form submitted something + window.parent.success(window.location.href); +} else { + const form = document.querySelector("form"); + form.submit(); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-with-action.sub.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-with-action.sub.html new file mode 100644 index 0000000000..97e800a561 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/form-with-action.sub.html @@ -0,0 +1,18 @@ +<!doctype html> + +<form action="{{GET[action]}}"> + <input type="text" name="name" value="value"> + <input type="submit" value="Submit"> +</form> + +<script> +"use strict"; + +if (window.location.search.startsWith("?name=value")) { + // The action pointed to ourself, so the form submitted something + window.parent.success(window.location.href); +} else { + const form = document.querySelector("form"); + form.submit(); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/target/form-action-url-target.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/target/form-action-url-target.html new file mode 100644 index 0000000000..d509f21924 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/resources/target/form-action-url-target.html @@ -0,0 +1,5 @@ +<!doctype html> +<script> +"use strict"; +window.parent.success(window.location.href); +</script> |