blob: 35f151b12d682a367ebcbbcc6dcf64f42fba0f97 [file] [log] [blame]
<!DOCTYPE html>
<meta charset=utf-8>
<title>Input element's type attribute changes state</title>
<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
<link rel=help href="https://html.spec.whatwg.org/multipage/#the-input-element">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
const INITIAL_VALUE = " foo\rbar ";
// Sanitize algorithm implementations only for values used in this test.
function sanitizeText(value) {
switch (value) {
case INITIAL_VALUE: return " foobar ";
case " foobar ": return value;
case "foobar": return value;
case "50": return value;
case "#000000": return value;
case "": return value;
default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
}
}
function sanitizeEmailOrUrl(value) {
switch (value) {
case INITIAL_VALUE: return "foobar";
case " foobar ": return "foobar";
case "foobar": return value;
case "50": return value;
case "#000000": return value;
case "": return value;
default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
}
}
function sanitizeTemporal(value) {
// We have no test cases using valid temporal values.
return "";
}
function sanitizeNumber(value) {
switch (value) {
case "50": return value;
default:
// We have no test cases using valid numbers other than "50".
return "";
}
}
function sanitizeRange(value) {
// We have no test cases using valid numbers other than "50".
return "50";
}
function sanitizeColor(value) {
// We have no test cases using valid colors other than "#000000".
return "#000000";
}
function browserSupportsInputTypeOf(inputType) {
var inputTest = document.createElement("input");
inputTest.type = inputType;
return (inputTest.type === inputType);
}
var types = [
{ type: "hidden" },
{ type: "text", sanitizer: sanitizeText },
{ type: "search", sanitizer: sanitizeText },
{ type: "tel", sanitizer: sanitizeText },
{ type: "url", sanitizer: sanitizeEmailOrUrl },
{ type: "email", sanitizer: sanitizeEmailOrUrl },
{ type: "password", sanitizer: sanitizeText },
{ type: "datetime-local", sanitizer: sanitizeTemporal },
{ type: "date", sanitizer: sanitizeTemporal },
{ type: "month", sanitizer: sanitizeTemporal },
{ type: "week", sanitizer: sanitizeTemporal },
{ type: "time", sanitizer: sanitizeTemporal },
{ type: "number", sanitizer: sanitizeNumber },
{ type: "range", sanitizer: sanitizeRange },
{ type: "color", sanitizer: sanitizeColor },
{ type: "checkbox", defaultValue: "on" },
{ type: "radio", defaultValue: "on" },
{ type: "file" },
{ type: "submit" },
{ type: "image" },
{ type: "reset" },
{ type: "button" }
];
const selectionStart = 2;
const selectionEnd = 5;
const selectionDirection = "backward";
// Obtain selectionDirection after setting it to "none".
// Some platforms don't support "none" direction, and "forward" is returned
// in such platforms.
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#set-the-selection-direction
function testNoneDirection() {
const input = document.createElement("input");
input.selectionDirection = "none";
return input.selectionDirection;
}
const noneDirectionResult = testNoneDirection();
for (var i = 0; i < types.length; i++) {
for (var j = 0; j < types.length; j++) {
if (types[i] != types[j]) {
test(function() {
assert_implements(browserSupportsInputTypeOf(types[i].type), "Support for input type " + types[i].type + " is required for this test.");
assert_implements(browserSupportsInputTypeOf(types[j].type), "Support for input type " + types[j].type + " is required for this test.");
var input = document.createElement("input");
var expected = INITIAL_VALUE;
input.type = types[i].type;
if (types[i].type === "file") {
assert_throws_dom("INVALID_STATE_ERR", function() {
input.value = expected;
});
assert_equals(input.value, "");
} else if (types[j].type === "file") {
input.value = expected;
input.type = types[j].type; // change state
assert_equals(input.value, "");
} else {
input.value = expected;
expected = input.value;
const previouslySelectable = (input.selectionStart !== null);
if (previouslySelectable) {
input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
}
input.type = types[j].type; // change state
// type[j] sanitization
if (types[j].sanitizer) {
expected = types[j].sanitizer(expected);
}
// type[j] defaultValue
if (expected === "" && types[j].defaultValue) {
expected = types[j].defaultValue;
}
assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state");
const nowSelectable = (input.selectionStart !== null);
if (nowSelectable) {
if (previouslySelectable) {
assert_equals(input.selectionStart, selectionStart, "selectionStart should be unchanged");
assert_equals(input.selectionEnd, selectionEnd, "selectionEnd should be unchanged");
assert_equals(input.selectionDirection, selectionDirection, "selectionDirection should be unchanged");
} else {
assert_equals(input.selectionStart, 0, "selectionStart should be 0");
assert_equals(input.selectionEnd, 0, "selectionEnd should be 0");
assert_equals(input.selectionDirection, noneDirectionResult,
`selectionDirection should be '{noneDirectionResult}'`);
}
}
}
}, "change state from " + types[i].type + " to " + types[j].type);
}
}
}
</script>