Bug 556743 - Update web-platform tests for labels attribute. r=smaug
authorJohn Dai <jdai@mozilla.com>
Mon, 05 Jun 2017 06:27:00 -0400
changeset 364420 766cadeccb1cdfe9e03d237f6adc51a723e4ccd1
parent 364419 170c00a5b2e092bcc0c7834f8c75932f414e14d4
child 364421 2cbb4884423e9bf711070daedf680e19b7e117fc
push id32040
push userkwierso@gmail.com
push dateSat, 17 Jun 2017 00:59:06 +0000
treeherdermozilla-central@bb8eab3c3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs556743
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 556743 - Update web-platform tests for labels attribute. r=smaug
dom/html/test/forms/test_button_attributes_reflection.html
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/html/dom/interfaces.html.ini
testing/web-platform/meta/html/semantics/forms/the-label-element/label-attributes.html.ini
testing/web-platform/meta/html/semantics/forms/the-label-element/labelable-elements.html.ini
testing/web-platform/meta/old-tests/submission/Infraware/Forms/contents/Forms/button_labels.html.ini
testing/web-platform/meta/old-tests/submission/Infraware/Forms/contents/Forms/input_labels.html.ini
testing/web-platform/tests/html/semantics/forms/the-label-element/iframe-label-attributes.html
testing/web-platform/tests/html/semantics/forms/the-label-element/label-attributes.html
testing/web-platform/tests/html/semantics/forms/the-label-element/labelable-elements.html
--- a/dom/html/test/forms/test_button_attributes_reflection.html
+++ b/dom/html/test/forms/test_button_attributes_reflection.html
@@ -123,15 +123,18 @@ is(typeof(document.createElement("button
 
 // .setCustomValidity()
 ok("setCustomValidity" in document.createElement("button"),
    "setCustomValidity() should be a method of the button element");
 is(typeof(document.createElement("button").setCustomValidity), "function",
    "button.setCustomValidity should be a function");
 
 // .labels
-todo("labels" in document.createElement("button"),
-     "button.labels isn't implemented yet");
-
+ok("labels" in document.createElement("button"),
+   "button.labels should be an IDL attribute of the button element");
+is(typeof(document.createElement("button").labels), "object",
+   "button.labels should be an object");
+ok(document.createElement("button").labels instanceof NodeList,
+   "button.labels sohuld be an instance of NodeList");
 </script>
 </pre>
 </body>
 </html>
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -56653,16 +56653,21 @@
      {}
     ]
    ],
    "html/semantics/forms/the-label-element/.gitkeep": [
     [
      {}
     ]
    ],
+   "html/semantics/forms/the-label-element/iframe-label-attributes.html": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/forms/the-legend-element/.gitkeep": [
     [
      {}
     ]
    ],
    "html/semantics/forms/the-meter-element/.gitkeep": [
     [
      {}
@@ -189025,22 +189030,26 @@
   "html/semantics/forms/the-input-element/week.html": [
    "851b1b794f820b1fb9b7ee57fe39f8f2977b7fe6",
    "testharness"
   ],
   "html/semantics/forms/the-label-element/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "html/semantics/forms/the-label-element/iframe-label-attributes.html": [
+   "5110391fe9ee5f04c2175bdaa1f38eeba0c40803",
+   "support"
+  ],
   "html/semantics/forms/the-label-element/label-attributes.html": [
-   "bb00ee78b9fa2343d85dcaa13376a832d376617a",
+   "4ce7bb05fecd15b76e40959bb9ab1e0b0adcd8da",
    "testharness"
   ],
   "html/semantics/forms/the-label-element/labelable-elements.html": [
-   "421328f898fb2487152f6fd8df315fc22ddea61a",
+   "80275984254360d8b713b5b330c18ae34138b670",
    "testharness"
   ],
   "html/semantics/forms/the-label-element/proxy-click-to-associated-element.html": [
    "49f17bfea3e8080fd8690b7be4bc3aa0c82e63e2",
    "testharness"
   ],
   "html/semantics/forms/the-legend-element/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
--- a/testing/web-platform/meta/html/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/html/dom/interfaces.html.ini
@@ -1055,79 +1055,61 @@
     expected: FAIL
 
   [HTMLInputElement interface: attribute valueLow]
     expected: FAIL
 
   [HTMLInputElement interface: attribute valueHigh]
     expected: FAIL
 
-  [HTMLInputElement interface: attribute labels]
-    expected: FAIL
-
   [HTMLInputElement interface: document.createElement("input") must inherit property "dirName" with the proper type (6)]
     expected: FAIL
 
   [HTMLInputElement interface: document.createElement("input") must inherit property "valueLow" with the proper type (37)]
     expected: FAIL
 
   [HTMLInputElement interface: document.createElement("input") must inherit property "valueHigh" with the proper type (38)]
     expected: FAIL
 
   [HTMLInputElement interface: document.createElement("input") must inherit property "labels" with the proper type (48)]
     expected: FAIL
 
   [HTMLButtonElement interface: attribute menu]
     expected: FAIL
 
-  [HTMLButtonElement interface: attribute labels]
-    expected: FAIL
-
   [HTMLButtonElement interface: document.createElement("button") must inherit property "menu" with the proper type (11)]
     expected: FAIL
 
   [HTMLButtonElement interface: document.createElement("button") must inherit property "labels" with the proper type (18)]
     expected: FAIL
 
   [HTMLSelectElement interface: attribute autocomplete]
     expected: FAIL
 
-  [HTMLSelectElement interface: attribute labels]
-    expected: FAIL
-
   [HTMLSelectElement interface: document.createElement("select") must inherit property "autocomplete" with the proper type (0)]
     expected: FAIL
 
-  [HTMLSelectElement interface: document.createElement("select") must inherit property "labels" with the proper type (26)]
-    expected: FAIL
-
   [HTMLTextAreaElement interface: attribute autocomplete]
     expected: FAIL
 
   [HTMLTextAreaElement interface: attribute dirName]
     expected: FAIL
 
   [HTMLTextAreaElement interface: attribute inputMode]
     expected: FAIL
 
-  [HTMLTextAreaElement interface: attribute labels]
-    expected: FAIL
-
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "autocomplete" with the proper type (0)]
     expected: FAIL
 
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "dirName" with the proper type (3)]
     expected: FAIL
 
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "inputMode" with the proper type (6)]
     expected: FAIL
 
-  [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "labels" with the proper type (25)]
-    expected: FAIL
-
   [HTMLKeygenElement interface: existence and properties of interface object]
     expected: FAIL
 
   [HTMLKeygenElement interface object length]
     expected: FAIL
 
   [HTMLKeygenElement interface: existence and properties of interface prototype object]
     expected: FAIL
@@ -1223,34 +1205,16 @@
     expected: FAIL
 
   [HTMLKeygenElement interface: calling setCustomValidity(DOMString) on document.createElement("keygen") with too few arguments must throw TypeError]
     expected: FAIL
 
   [HTMLKeygenElement interface: document.createElement("keygen") must inherit property "labels" with the proper type (13)]
     expected: FAIL
 
-  [HTMLOutputElement interface: attribute labels]
-    expected: FAIL
-
-  [HTMLOutputElement interface: document.createElement("output") must inherit property "labels" with the proper type (12)]
-    expected: FAIL
-
-  [HTMLProgressElement interface: attribute labels]
-    expected: FAIL
-
-  [HTMLProgressElement interface: document.createElement("progress") must inherit property "labels" with the proper type (3)]
-    expected: FAIL
-
-  [HTMLMeterElement interface: attribute labels]
-    expected: FAIL
-
-  [HTMLMeterElement interface: document.createElement("meter") must inherit property "labels" with the proper type (6)]
-    expected: FAIL
-
   [HTMLMenuItemElement interface: attribute default]
     expected: FAIL
 
   [HTMLMenuItemElement interface: attribute command]
     expected: FAIL
 
   [RelatedEvent interface: existence and properties of interface object]
     expected: FAIL
@@ -2750,85 +2714,16 @@
     expected: FAIL
 
   [HTMLMediaElement interface: new Audio() must inherit property "audioTracks" with the proper type (38)]
     expected: FAIL
 
   [HTMLMediaElement interface: new Audio() must inherit property "videoTracks" with the proper type (39)]
     expected: FAIL
 
-  [HTMLInputElement interface: document.createElement("input") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("text") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("hidden") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("search") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("tel") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("url") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("email") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("password") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("date") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("month") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("week") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("time") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("datetime-local") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("number") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("range") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("color") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("checkbox") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("radio") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("file") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("submit") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("image") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("reset") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
-  [HTMLInputElement interface: createInput("button") must inherit property "labels" with the proper type (46)]
-    expected: FAIL
-
   [CanvasRenderingContext2D interface: operation getTransform()]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: operation setTransform(unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double)]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: operation setTransform(DOMMatrixInit)]
     expected: FAIL
@@ -3374,19 +3269,16 @@
     expected: FAIL
 
   [Document interface: document.implementation.createDocument(null, "", null) must inherit property "oncuechange" with the proper type (95)]
     expected: FAIL
 
   [Document interface: document.implementation.createDocument(null, "", null) must inherit property "onmousewheel" with the proper type (126)]
     expected: FAIL
 
-  [HTMLButtonElement interface: document.createElement("button") must inherit property "labels" with the proper type (17)]
-    expected: FAIL
-
   [HTMLScriptElement interface: attribute noModule]
     expected: FAIL
 
   [HTMLScriptElement interface: attribute nonce]
     expected: FAIL
 
   [HTMLScriptElement interface: document.createElement("script") must inherit property "noModule" with the proper type (2)]
     expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/forms/the-label-element/label-attributes.html.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[label-attributes.html]
-  type: testharness
-  [A non-control follows by a control with same ID.]
-    expected: FAIL
-
-  [A form control has multiple labels.]
-    expected: FAIL
-
-  [A form control has no label 1.]
-    expected: FAIL
-
-  [A form control has no label 2.]
-    expected: FAIL
-
-  [A form control has an implicit label.]
-    expected: FAIL
-
--- a/testing/web-platform/meta/html/semantics/forms/the-label-element/labelable-elements.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-label-element/labelable-elements.html.ini
@@ -1,32 +1,6 @@
 [labelable-elements.html]
   type: testharness
-  [Check if the output element can access 'labels']
-    expected: FAIL
-
-  [Check if the progress element can access 'labels']
-    expected: FAIL
-
-  [Check if the select element can access 'labels']
-    expected: FAIL
-
-  [Check if the textarea element can access 'labels']
-    expected: FAIL
-
-  [Check if the button element can access 'labels']
-    expected: FAIL
-
-  [Check if the hidden input element can access 'labels']
-    expected: FAIL
-
-  [Check if the input element in radio state can access 'labels']
-    expected: FAIL
-
-  [Check if the meter element can access 'labels']
-    expected: FAIL
-
-  [Check if the hidden input element has null 'labels']
-    expected: FAIL
-
   [Check if the keygen element is not a labelable element]
     expected: FAIL
-
+  [Check if the keygen element can access 'labels']
+    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/old-tests/submission/Infraware/Forms/contents/Forms/button_labels.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[button_labels.html]
-  type: testharness
-  [Forms]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/old-tests/submission/Infraware/Forms/contents/Forms/input_labels.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[input_labels.html]
-  type: testharness
-  [Forms]
-    expected: FAIL
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-label-element/iframe-label-attributes.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <label>
+      <div id="div1"></div>
+    </label>
+    <label for="test13"></label>
+  </body>
+</html>
\ No newline at end of file
--- a/testing/web-platform/tests/html/semantics/forms/the-label-element/label-attributes.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-label-element/label-attributes.html
@@ -27,20 +27,63 @@
   </label>
 
   <label id="lbl4" for="">
     <input id="" class="class2">
   </label>
 
   <label id="lbl5" for="test7"></label>
   <input id="test7">
+
+  <label id="lbl7">
+    <label id="lbl8">
+      <div id="div1">
+        <input id="test8">
+      </div>
+    </label>
+  </label>
+  <div id="div2"></div>
+
+ <label id="lbl9">
+   <label id="lbl10" for="test10">
+    <div id="div3">
+      <input id="test9">
+    </div>
+  </label>
+ </label>
+ <div id="div4"><input id="test10"></div>
+
+  <label id="lbl11">
+    <object id="obj">
+      <input id="test11">
+      <input id="test12">
+    </object>
+  </label>
+  <label id="lbl12" for="test12"><div id="div5"></div></label>
+
+  <label id="lbl13">
+    <p id="p1">
+      <input id="test13">
+    </p>
+  </label>
+
+  <div id="div6">
+    <div id="div7">
+      <label id="lbl14">
+        <label id="lbl15" for="test15">
+          <input id="test14">
+        </label>
+      </label>
+    </div>
+  </div>
+  <input id="test15">
 </form>
 
 <label id="lbl6" for="test7"></label>
-
+<div id="content" style="display: none">
 <script>
 
   //control attribute
   test(function () {
     assert_not_equals(document.getElementById("lbl0").control, document.getElementById("test0"),
                       "An element that's not a labelable element can't be a label element's labeled control.");
     assert_equals(document.getElementById("lbl0").control, null,
                   "A label element whose 'for' attribute doesn't reference any labelable element shouldn't have any labeled control.");
@@ -52,23 +95,28 @@
     assert_not_equals(label.control, document.getElementById("test1"),
                       "A label element not in a document should not label an element in a document.");
     document.body.appendChild(label);
     assert_equals(label.control, document.getElementById("test1"));
     label.remove();
   }, "A label element not in a document can not label any element in the document.");
 
   test(function () {
+    var labels = document.getElementById("test3").labels;
     assert_equals(document.getElementById("lbl1").control, document.getElementById("test3"),
                   "The first labelable descendant of a label element should be its labeled control.");
 
     var input = document.createElement("input");
     document.getElementById("lbl1").insertBefore(input, document.getElementById("test2"));
     assert_equals(document.getElementById("lbl1").control, input,
                   "The first labelable descendant of a label element in tree order should be its labeled control.");
+    assert_equals(input.labels.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_equals(labels.length, 0,
+                  "The number of labels should be 0 if it's not the first labelable descendant of a label element.");
     input.remove();
   }, "The labeled control for a label element that has no 'for' attribute is the first labelable element which is a descendant of that label element.");
 
   test(function () {
     assert_equals(document.getElementById("lbl2").control, null,
                   "The label's 'control' property should return null if its 'for' attribute points to an inexistent element.");
   }, "The 'for' attribute points to an inexistent id.");
 
@@ -96,16 +144,178 @@
     newLabel.htmlFor = "test7";
     document.getElementById("fm").insertBefore(newLabel, document.getElementById("lbl0"));
     assert_array_equals(document.getElementById("test7").labels, [newLabel, document.getElementById("lbl5"), document.getElementById("lbl6")],
                         "The labels for a form control should be returned in tree order.");
     newLabel.remove();
   }, "A form control has multiple labels.");
 
   test(function () {
+    var labels = document.getElementById("test8").labels;
+    assert_true(labels instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels.length, 2,
+                  "The form control has two ancestors with no explicit associated label, and is the first labelable descendant.");
+    assert_array_equals(labels, [document.getElementById("lbl7"), document.getElementById("lbl8")],
+                        "The labels for a form control should be returned in tree order.");
+
+    document.getElementById('div2').insertBefore(document.getElementById('div1'), document.getElementById('div2').firstChild);
+    assert_equals(labels.length, 0,
+                  "The number of labels should be 0 after the labelable element is moved to outside of nested associated labels.");
+  }, "A labelable element is moved to outside of nested associated labels.");
+
+  test(function () {
+    var labels1 = document.getElementById("test9").labels;
+    var labels2 = document.getElementById("test10").labels;
+    assert_true(labels1 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_true(labels2 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels1.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
+    assert_array_equals(labels1, [document.getElementById("lbl9")],
+                        "The labels for a form control should be returned in tree order.");
+    assert_array_equals(labels2, [document.getElementById("lbl10")],
+                        "The labels for a form control should be returned in tree order.");
+    document.getElementById('div3').insertBefore(document.getElementById('div4'), document.getElementById('div3').firstChild);
+    assert_equals(labels1.length, 0,
+                  "The number of labels should be 0 if it's not the first labelable descendant of a label element.");
+    assert_equals(labels2.length, 2,
+                  "The form control has an ancestor with an explicit associated label, and is the first labelable descendant.");
+  }, "A labelable element is moved to inside of nested associated labels.");
+
+  test(function () {
+    var labels1 = document.getElementById("test11").labels;
+    var labels2 = document.getElementById("test12").labels;
+    assert_true(labels1 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_true(labels2 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels1.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and it is the first labelable descendant.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels should be 1 since there is a label with a 'for' attribute associated with this labelable element.");
+    assert_array_equals(labels1, [document.getElementById("lbl11")],
+                        "The labels for a form control should be returned in tree order.");
+    assert_array_equals(labels2, [document.getElementById("lbl12")],
+                        "The labels for a form control should be returned in tree order.");
+    document.getElementById('div5').appendChild(document.getElementById('obj'));
+    assert_equals(labels1.length, 0,
+                  "The number of labels should be 0 after the labelable element is moved to outside of associated label.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels should be 1 after the labelable element is moved to outside of associated label.");
+  }, "A labelable element which is a descendant of non-labelable element is moved to outside of associated label.");
+
+  async_test(function () {
+    var labels = document.getElementById("test13").labels;
+    assert_true(labels instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_array_equals(labels, [document.getElementById("lbl13")],
+                        "The labels for a form control should be returned in tree order.");
+    let iframe = document.createElement('iframe');
+
+    iframe.onload = this.step_func_done(() => {
+      iframe.contentWindow.document.getElementById("div1").appendChild(document.getElementById("p1"));
+      assert_equals(labels.length, 2,
+                    "The number of labels should be 2 after the labelable element is moved to iframe.");
+    });
+
+    iframe.setAttribute('src', 'http://web-platform.test:8000/html/semantics/forms/the-label-element/iframe-label-attributes.html');
+    document.body.appendChild(iframe);
+  }, "A labelable element is moved to iframe.");
+
+  test(function () {
+    var labels1 = document.getElementById("test14").labels;
+    var labels2 = document.getElementById("test15").labels;
+    assert_true(labels1 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels1.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
+    assert_array_equals(labels1, [document.getElementById("lbl14")],
+                        "The labels for a form control should be returned in tree order.");
+
+    document.getElementById('div6').removeChild(document.getElementById('div7'));
+    assert_equals(labels1.length, 0,
+                  "The number of labels should be 0 after the labelable element is removed.");
+    assert_equals(labels2.length, 0,
+                  "The number of labels should be 0 since there is no label with a 'for' attribute associated with this labelable element.");
+  }, "A div element which contains labelable element is removed.");
+
+  test(function () {
+    // <label><input id="test16"><label for="test16"></label></label>
+    var label1 = document.createElement('label');
+    label1.innerHTML = "<input id='test16'>";
+    var label2 = document.createElement('label');
+    label2.htmlFor = "test16";
+    label1.appendChild(label2);
+
+    var input = label1.firstChild;
+    var labels = input.labels;
+
+    assert_equals(labels.length, 2,
+                  "The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
+    assert_true(labels instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(label1.control, input, "The first labelable descendant of a label element should be its labeled control.");
+    assert_equals(label2.control, input, "The labeled cotrol should be associated with the control whose ID is equal to the value of the 'for' attribute.");
+  }, "A labelable element not in a document can label element in the same tree.");
+
+  test(function () {
+    var isShadowDOMV0;
+    if ("createShadowRoot" in document.getElementById('content')) {
+      isShadowDOMV0 = true;
+    }
+    var root1;
+    if (isShadowDOMV0) {
+      root1 = document.getElementById('content').createShadowRoot();
+    } else {
+      root1 = document.getElementById('content').attachShadow({mode: 'open'});
+    }
+    assert_true(root1 instanceof DocumentFragment,
+                "ShadowRoot should be an instance of DocumentFragment.");
+    // <label><input id="shadow1"/></label><div id="div1"></div>
+    var label1 = document.createElement('label');
+    var input1 = document.createElement('input');
+    input1.setAttribute("id", "shadow1");
+    label1.appendChild(input1);
+    root1.appendChild(label1);
+
+    var div1 = document.createElement('div');
+    label1.appendChild(div1);
+    // <label for="shadow2"></label><input id="shadow2"/>
+    var root2;
+    if (isShadowDOMV0) {
+      root2 = div1.createShadowRoot();
+    } else {
+      root2 = div1.attachShadow({mode: 'open'});
+    }
+
+    assert_true(root2 instanceof DocumentFragment,
+                "ShadowRoot should be an instance of DocumentFragment.");
+    var label2 = document.createElement('label');
+    label2.setAttribute("for", "shadow2");
+
+    var input2 = document.createElement('input');
+    input2.setAttribute("id", "shadow2");
+    root2.appendChild(label2);
+    root2.appendChild(input2);
+
+    assert_equals(root1.getElementById("shadow1").labels.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and it is the first labelable descendant.");
+    assert_equals(root2.getElementById("shadow2").labels.length, 1,
+                  "The number of labels should be 1 since there is a label with a 'for' attribute associated with this labelable element.");
+  }, "A labelable element inside the shadow DOM.");
+
+  test(function () {
     var labels = document.getElementById("test3").labels;
     assert_true(labels instanceof NodeList, "A form control's 'labels' property should be an instance of a NodeList.");
     assert_equals(labels.length, 1, "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
   }, "A form control has an implicit label.");
 
   test(function () {
     var labels = document.getElementById("test4").labels;
     assert_true(labels instanceof NodeList, "A form control's 'labels' property should be an instance of a NodeList.");
--- a/testing/web-platform/tests/html/semantics/forms/the-label-element/labelable-elements.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-label-element/labelable-elements.html
@@ -99,16 +99,17 @@ test(function() {
   });
 
   hiddenInput.type = "text";
   testLabelsAttr("testHidden", "lbl5");
   var labels = hiddenInput.labels;
 
   hiddenInput.type = "hidden";
   assert_equals(labels.length, 0, "Retained .labels NodeList should be empty after input type changed to hidden");
+  assert_equals(hiddenInput.labels, null, ".labels NodeList should be null after input type changed to hidden");
 
   hiddenInput.type = "checkbox";
   assert_true(labels === hiddenInput.labels, ".labels property must return the [SameObject] after input type is toggled back from 'hidden'");
   assert_equals(hiddenInput.labels.length, 1, ".labels NodeList should contain the input after the input type is changed from 'hidden' to 'checkbox'");
 }, "Check if the hidden input element has null 'labels'");
 
 test(function() {
   assert_equals(document.getElementById("lbl6").control.id, "testRadio", "An input  element in radio state should be labelable.");