Fix validity.valueMissing tests (#21031)

These changes fix expectations for validity.valueMissing and validity.valid for disabled/readonly textual elements. This fixes #21007.
diff --git a/html/semantics/forms/constraints/form-validation-validity-valid.html b/html/semantics/forms/constraints/form-validation-validity-valid.html
index cec5dcb..03655ff 100644
--- a/html/semantics/forms/constraints/form-validation-validity-valid.html
+++ b/html/semantics/forms/constraints/form-validation-validity-valid.html
@@ -15,7 +15,7 @@
       types: ["text", "search", "tel", "password"],
       testData: [
         {conditions: {pattern: "[A-Z]", value: "abc"}, expected: false, name: "[target] validity.valid must be false if validity.patternMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -24,7 +24,7 @@
       testData: [
         {conditions: {pattern: "http://www.example.com", value: "http://www.example.net"}, expected: false, name: "[target] validity.valid must be false if validity.patternMismatch is true"},
         {conditions: {value: "abc"}, expected: false, name: "[target] validity.valid must be false if validity.typeMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -33,7 +33,7 @@
       testData: [
         {conditions: {pattern: "test@example.com", value: "test@example.net"}, expected: false, name: "[target] validity.valid must be false if validity.patternMismatch is true"},
         {conditions: {value: "abc"}, expected: false, name: "[target] validity.valid must be false if validity.typeMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -43,7 +43,7 @@
         {conditions: {max: "2000-01-01T12:00:00", value: "2001-01-01T12:00:00"}, expected: false, name: "[target] validity.valid must be false if validity.rangeOverflow is true"},
         {conditions: {min: "2001-01-01T12:00:00", value: "2000-01-01T12:00:00"}, expected: false, name: "[target] validity.valid must be false if validity.rangeUnderflow is true"},
         {conditions: {step: 2 * 60 * 1000, value: "2001-01-01T12:03:00"}, expected: false, name: "[target] validity.valid must be false if validity.stepMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -53,7 +53,7 @@
         {conditions: {max: "2000-01-01", value: "2001-01-01"}, expected: false, name: "[target] validity.valid must be false if validity.rangeOverflow is true"},
         {conditions: {min: "2001-01-01", value: "2000-01-01"}, expected: false, name: "[target] validity.valid must be false if validity.rangeUnderflow is true"},
         {conditions: {step: 2 * 1 * 86400000, value: "2000-01-03"}, expected: false, name: "[target] validity.valid must be false if validity.stepMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -64,7 +64,7 @@
         {conditions: {min: "2001-01", value: "2000-01"}, expected: false, name: "[target] validity.valid must be false if validity.rangeUnderflow is true"},
         // Step checks that "months since Jan 1970" is evenly divisible by `step`
         {conditions: {step: 3, value: "2001-02"}, expected: false, name: "[target] validity.valid must be false if validity.stepMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -74,7 +74,7 @@
         {conditions: {max: "2000-W01", value: "2001-W01"}, expected: false, name: "[target] validity.valid must be false if validity.rangeOverflow is true"},
         {conditions: {min: "2001-W01", value: "2000-W01"}, expected: false, name: "[target] validity.valid must be false if validity.rangeUnderflow is true"},
         {conditions: {step: 2 * 1 * 604800000, value: "2001-W03"}, expected: false, name: "[target] validity.valid must be false if validity.stepMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -84,7 +84,7 @@
         {conditions: {max: "12:00:00", value: "13:00:00"}, expected: false, name: "[target] validity.valid must be false if validity.rangeOverflow is true"},
         {conditions: {min: "12:00:00", value: "11:00:00"}, expected: false, name: "[target] validity.valid must be false if validity.rangeUnderflow is true"},
         {conditions: {step: 2 * 60 * 1000, value: "12:03:00"}, expected: false, name: "[target] validity.valid must be false if validity.stepMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -94,7 +94,7 @@
         {conditions: {max: "5", value: "6"}, expected: false, name: "[target] validity.valid must be false if validity.rangeOverflow is true"},
         {conditions: {min: "5", value: "4"}, expected: false, name: "[target] validity.valid must be false if validity.rangeUnderflow is true"},
         {conditions: {step: 2 * 1 * 1, value: "3"}, expected: false, name: "[target] validity.valid must be false if validity.stepMismatch is true"},
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     },
     {
@@ -122,7 +122,7 @@
       tag: "textarea",
       types: [],
       testData: [
-        {conditions: {required: true, value: ""}, expected: false, name: "[target] validity.valid must be false if validity.valueMissing is true"}
+        {conditions: {required: true, value: ""}, expected: false, expectedImmutable: true, name: "[target] validity.valid must be false if validity.valueMissing is true"}
       ]
     }
   ];
diff --git a/html/semantics/forms/constraints/form-validation-validity-valueMissing.html b/html/semantics/forms/constraints/form-validation-validity-valueMissing.html
index 3c9e4c4..2e1c666 100644
--- a/html/semantics/forms/constraints/form-validation-validity-valueMissing.html
+++ b/html/semantics/forms/constraints/form-validation-validity-valueMissing.html
@@ -16,7 +16,7 @@
       testData: [
         {conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
         {conditions: {required: true, value: "abc"}, expected: false, name: "[target] The value is not empty and required is true"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value is empty and required is true"}
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value is empty and required is true"}
       ]
     },
     {
@@ -27,13 +27,13 @@
         {conditions: {required: true, value: "2000-12-10T12:00:00"}, expected: false, name: "[target] Valid local date and time string(2000-12-10T12:00:00)"},
         {conditions: {required: true, value: "2000-12-10 12:00"}, expected: false, name: "[target] Valid local date and time string(2000-12-10 12:00)"},
         {conditions: {required: true, value: "1979-10-14T12:00:00.001"}, expected: false, name: "[target] Valid local date and time string(1979-10-14T12:00:00.001)"},
-        {conditions: {required: true, value: 1234567}, expected: true, name: "[target] The value attribute is a number(1234567)"},
-        {conditions: {required: true, value: new Date()}, expected: true, name: "[target] The value attribute is a Date object"},
-        {conditions: {required: true, value: "1979-10-99 99:99"}, expected: true, name: "[target] Invalid local date and time string(1979-10-99 99:99)"},
+        {conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
+        {conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a Date object"},
+        {conditions: {required: true, value: "1979-10-99 99:99"}, expected: true, expectedImmutable: false, name: "[target] Invalid local date and time string(1979-10-99 99:99)"},
         {conditions: {required: true, value: "1979-10-14 12:00:00"}, expected: false, name: "[target] Valid local date and time string(1979-10-14 12:00:00)"},
-        {conditions: {required: true, value: "2001-12-21  12:00"}, expected: true, name: "[target] Invalid local date and time string(2001-12-21  12:00)-two white space"},
-        {conditions: {required: true, value: "abc"}, expected: true, name: "[target] the value attribute is a string(abc)"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value attribute is empty string"}
+        {conditions: {required: true, value: "2001-12-21  12:00"}, expected: true, expectedImmutable: false, name: "[target] Invalid local date and time string(2001-12-21  12:00)-two white space"},
+        {conditions: {required: true, value: "abc"}, expected: true, expectedImmutable: false, name: "[target] the value attribute is a string(abc)"},
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
       ]
     },
     {
@@ -43,12 +43,12 @@
         {conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
         {conditions: {required: true, value: "2000-12-10"}, expected: false, name: "[target] Valid date string(2000-12-10)"},
         {conditions: {required: true, value: "9999-01-01"}, expected: false, name: "[target] Valid date string(9999-01-01)"},
-        {conditions: {required: true, value: 1234567}, expected: true, name: "[target] The value attribute is a number(1234567)"},
-        {conditions: {required: true, value: new Date()}, expected: true, name: "[target] The value attribute is a Date object"},
-        {conditions: {required: true, value: "9999-99-99"}, expected: true, name: "[target] Invalid date string(9999-99-99)"},
-        {conditions: {required: true, value: "37/01/01"}, expected: true, name: "[target] Invalid date string(37-01-01)"},
-        {conditions: {required: true, value: "2000/01/01"}, expected: true, name: "[target] Invalid date string(2000/01/01)"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value attribute is empty string"}
+        {conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
+        {conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a Date object"},
+        {conditions: {required: true, value: "9999-99-99"}, expected: true, expectedImmutable: false, name: "[target] Invalid date string(9999-99-99)"},
+        {conditions: {required: true, value: "37/01/01"}, expected: true, expectedImmutable: false, name: "[target] Invalid date string(37-01-01)"},
+        {conditions: {required: true, value: "2000/01/01"}, expected: true, expectedImmutable: false, name: "[target] Invalid date string(2000/01/01)"},
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
       ]
     },
     {
@@ -58,12 +58,12 @@
         {conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
         {conditions: {required: true, value: "2000-12"}, expected: false, name: "[target] Valid month string(2000-12)"},
         {conditions: {required: true, value: "9999-01"}, expected: false, name: "[target] Valid month string(9999-01)"},
-        {conditions: {required: true, value: 1234567}, expected: true, name: "[target] The value attribute is a number(1234567)"},
-        {conditions: {required: true, value: new Date()}, expected: true, name: "[target] The value attribute is a Date object"},
-        {conditions: {required: true, value: "2000-99"}, expected: true, name: "[target] Invalid month string(2000-99)"},
-        {conditions: {required: true, value: "37-01"}, expected: true, name: "[target] Invalid month string(37-01)"},
-        {conditions: {required: true, value: "2000/01"}, expected: true, name: "[target] Invalid month string(2000/01)"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value attribute is empty string"}
+        {conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
+        {conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a Date object"},
+        {conditions: {required: true, value: "2000-99"}, expected: true, expectedImmutable: false, name: "[target] Invalid month string(2000-99)"},
+        {conditions: {required: true, value: "37-01"}, expected: true, expectedImmutable: false, name: "[target] Invalid month string(37-01)"},
+        {conditions: {required: true, value: "2000/01"}, expected: true, expectedImmutable: false, name: "[target] Invalid month string(2000/01)"},
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
       ]
     },
     {
@@ -73,12 +73,12 @@
         {conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
         {conditions: {required: true, value: "2000-W12"}, expected: false, name: "[target] Valid week string(2000-W12)"},
         {conditions: {required: true, value: "9999-W01"}, expected: false, name: "[target] Valid week string(9999-W01)"},
-        {conditions: {required: true, value: 1234567}, expected: true, name: "[target] The value attribute is a number(1234567)"},
-        {conditions: {required: true, value: new Date()}, expected: true, name: "[target] The value attribute is a Date object"},
-        {conditions: {required: true, value: "2000-W99"}, expected: true, name: "[target] Invalid week string(2000-W99)"},
-        {conditions: {required: true, value: "2000-W00"}, expected: true, name: "[target] invalid week string(2000-W00)"},
-        {conditions: {required: true, value: "2000-w01"}, expected: true, name: "[target] invalid week string(2000-w01)"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value attribute is empty string"}
+        {conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
+        {conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a Date object"},
+        {conditions: {required: true, value: "2000-W99"}, expected: true, expectedImmutable: false, name: "[target] Invalid week string(2000-W99)"},
+        {conditions: {required: true, value: "2000-W00"}, expected: true, expectedImmutable: false, name: "[target] invalid week string(2000-W00)"},
+        {conditions: {required: true, value: "2000-w01"}, expected: true, expectedImmutable: false, name: "[target] invalid week string(2000-w01)"},
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
       ]
     },
     {
@@ -91,13 +91,13 @@
         {conditions: {required: true, value: "12:00:00.001"}, expected: false, name: "[target] Valid time string(12:00:60.001)"},
         {conditions: {required: true, value: "12:00:00.01"}, expected: false, name: "[target] Valid time string(12:00:60.01)"},
         {conditions: {required: true, value: "12:00:00.1"}, expected: false, name: "[target] Valid time string(12:00:60.1)"},
-        {conditions: {required: true, value: 1234567}, expected: true, name: "[target] The value attribute is a number(1234567)"},
-        {conditions: {required: true, value: new Date()}, expected: true, name: "[target] The value attribute is a time object"},
-        {conditions: {required: true, value: "25:00:00"}, expected: true, name: "[target] Invalid time string(25:00:00)"},
-        {conditions: {required: true, value: "12:60:00"}, expected: true, name: "[target] Invalid time string(12:60:00)"},
-        {conditions: {required: true, value: "12:00:60"}, expected: true, name: "[target] Invalid time string(12:00:60)"},
-        {conditions: {required: true, value: "12:00:00:001"}, expected: true, name: "[target] Invalid time string(12:00:00:001)"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value attribute is empty string"}
+        {conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
+        {conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a time object"},
+        {conditions: {required: true, value: "25:00:00"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(25:00:00)"},
+        {conditions: {required: true, value: "12:60:00"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(12:60:00)"},
+        {conditions: {required: true, value: "12:00:60"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(12:00:60)"},
+        {conditions: {required: true, value: "12:00:00:001"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(12:00:00:001)"},
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
       ]
     },
     {
@@ -110,11 +110,11 @@
         {conditions: {required: true, value: "123.01e-10"}, expected: false, name: "[target] Value is a number in scientific notation form(e is in lowercase)"},
         {conditions: {required: true, value: "123.01E+10"}, expected: false, name: "[target] Value is a number in scientific notation form(E is in uppercase)"},
         {conditions: {required: true, value: "-0"}, expected: false, name: "[target] Value is -0"},
-        {conditions: {required: true, value: " 123 "}, expected: true, name: "[target] Value is a number with some white spaces"},
-        {conditions: {required: true, value: Math.pow(2, 1024)}, expected: true, name: "[target] Value is Math.pow(2, 1024)"},
-        {conditions: {required: true, value: Math.pow(-2, 1024)}, expected: true, name: "[target] Value is Math.pow(-2, 1024)"},
-        {conditions: {required: true, value: "abc"}, expected: true, name: "[target] Value is a string that cannot be converted to a number"},
-        {conditions: {required: true, value: ""}, expected: true, name: "[target] The value attribute is empty string"}
+        {conditions: {required: true, value: " 123 "}, expected: true, expectedImmutable: false, name: "[target] Value is a number with some white spaces"},
+        {conditions: {required: true, value: Math.pow(2, 1024)}, expected: true, expectedImmutable: false, name: "[target] Value is Math.pow(2, 1024)"},
+        {conditions: {required: true, value: Math.pow(-2, 1024)}, expected: true, expectedImmutable: false, name: "[target] Value is Math.pow(-2, 1024)"},
+        {conditions: {required: true, value: "abc"}, expected: true, expectedImmutable: false, name: "[target] Value is a string that cannot be converted to a number"},
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
       ]
     },
     {
@@ -159,7 +159,7 @@
       testData: [
         {conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
         {conditions: {required: true, value: "abc"}, expected: false, name: "[target] The value is not empty"},
-        {conditions: {required: true, value: ""}, expected: true  , name: "[target] The value is empty"}
+        {conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value is empty"}
       ]
     }
   ];
diff --git a/html/semantics/forms/constraints/support/validator.js b/html/semantics/forms/constraints/support/validator.js
index 48c3a5b..33508fb 100644
--- a/html/semantics/forms/constraints/support/validator.js
+++ b/html/semantics/forms/constraints/support/validator.js
@@ -5,8 +5,8 @@
     test(function() {
       self.pre_check(ctl, 'tooLong');
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.tooLong,
               'The validity.tooLong should be true' + condStr);
@@ -23,8 +23,8 @@
     test(function () {
       self.pre_check(ctl, "tooShort");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.tooShort,
               'The validity.tooShort should be true' + condStr);
@@ -41,8 +41,8 @@
     test(function () {
       self.pre_check(ctl, "patternMismatch");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.patternMismatch,
               'The validity.patternMismatch should be true' + condStr);
@@ -59,8 +59,8 @@
     test(function () {
       self.pre_check(ctl, "valueMissing");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.valueMissing,
               'The validity.valueMissing should be true' + condStr);
@@ -77,8 +77,8 @@
     test(function () {
       self.pre_check(ctl, "typeMismatch");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.typeMismatch,
               'The validity.typeMismatch should be true' + condStr);
@@ -95,8 +95,8 @@
     test(function () {
       self.pre_check(ctl, "rangeOverflow");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.rangeOverflow,
               'The validity.rangeOverflow should be true' + condStr);
@@ -113,8 +113,8 @@
     test(function () {
       self.pre_check(ctl, "rangeUnderflow");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.rangeUnderflow,
               'The validity.rangeUnderflow should be true' + condStr);
@@ -131,8 +131,8 @@
     test(function () {
       self.pre_check(ctl, "stepMismatch");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.stepMismatch,
               'The validity.stepMismatch should be true' + condStr);
@@ -149,8 +149,8 @@
     test(function () {
       self.pre_check(ctl, "badInput");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.badInput,
               'The validity.badInput should be true' + condStr);
@@ -167,14 +167,14 @@
     test(function () {
       self.pre_check(ctl, "customError");
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected) {
+        const {ctl, expected, condStr} = val;
+        if (expected) {
           assert_true(
               ctl.validity.customError,
               'The validity.customError attribute should be true' + condStr);
           // validationMessage returns the empty string if ctl is barred from
-          // constraint validation, which happens if ctl is disabled.
-          if (ctl.disabled) {
+          // constraint validation, which happens if ctl is disabled or readOnly.
+          if (ctl.disabled || ctl.readOnly) {
             assert_equals(
                 ctl.validationMessage, '',
                 'The validationMessage attribute must be empty' + condStr);
@@ -200,8 +200,8 @@
     var self = this;
     test(function () {
       self.iterate_over(ctl, data).forEach(function(val) {
-        const {ctl, data, condStr} = val;
-        if (data.expected)
+        const {ctl, expected, condStr} = val;
+        if (expected)
           assert_true(
               ctl.validity.valid,
               'The validity.valid should be true' + condStr);
@@ -389,39 +389,54 @@
   },
 
   iterate_over: function(ctl, data) {
-    // Iterate over normal, disabled, readonly, and both.
+    // Iterate over normal, disabled, readonly, and both (if applicable).
+    var ctlNormal = ctl.cloneNode(true);
+    this.set_conditions(ctlNormal, data.conditions);
+    if (data.dirty)
+      this.set_dirty(ctlNormal);
+
     var ctlDisabled = ctl.cloneNode(true);
     this.set_conditions(ctlDisabled, data.conditions);
     if (data.dirty)
       this.set_dirty(ctlDisabled);
     ctlDisabled.disabled = true;
 
-    var ctlReadonly = ctl.cloneNode(true);
-    this.set_conditions(ctlReadonly, data.conditions);
-    if (data.dirty)
-      this.set_dirty(ctlReadonly);
-    ctlReadonly.readonly = true;
+    var expectedImmutable =
+      data.expectedImmutable !== undefined ? data.expectedImmutable : data.expected;
 
-    var ctlBoth = ctl.cloneNode(true);
-    this.set_conditions(ctlBoth, data.conditions);
-    if (data.dirty)
-      this.set_dirty(ctlBoth);
-    ctlBoth.disabled = true;
-    ctlBoth.readonly = true;
+    var variants = [
+      {ctl: ctlNormal, expected: data.expected, condStr: '.'},
+      {ctl: ctlDisabled, expected: expectedImmutable, condStr: ', when control is disabled.'},
+    ];
 
-    ctl = ctl.cloneNode(true);
-    this.set_conditions(ctl, data.conditions);
+    if ('readOnly' in ctl) {
+      var ctlReadonly = ctl.cloneNode(true);
+      this.set_conditions(ctlReadonly, data.conditions);
+      if (data.dirty)
+        this.set_dirty(ctlReadonly);
+      ctlReadonly.readOnly = true;
 
-    return [
-      {ctl: ctl, data: data, condStr: '.'},
-      {ctl: ctlDisabled, data: data, condStr: ', when control is disabled.'},
-      {ctl: ctlReadonly, data: data, condStr: ', when control is readonly.'},
-      {
+      var ctlBoth = ctl.cloneNode(true);
+      this.set_conditions(ctlBoth, data.conditions);
+      if (data.dirty)
+        this.set_dirty(ctlBoth);
+      ctlBoth.disabled = true;
+      ctlBoth.readOnly = true;
+
+      variants.push({
+        ctl: ctlReadonly,
+        expected: expectedImmutable,
+        condStr: ', when control is readonly.'
+      });
+
+      variants.push({
         ctl: ctlBoth,
-        data: data,
+        expected: expectedImmutable,
         condStr: ', when control is disabled & readonly.'
-      },
-    ]
+      });
+    }
+
+    return variants;
   },
 
   run_test: function(testee, method) {