| <!DOCTYPE html> |
| <meta charset="utf-8" /> |
| <title>CSS Selectors Invalidation: input pseudo classes in :has() argument</title> |
| <link rel="author" title="Byungwoo Lee" href="blee@igalia.com"> |
| <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <style> |
| .ancestor:has(#checkme:checked) { color: green } |
| .ancestor:has(#checkme:indeterminate) { color: yellowgreen } |
| .ancestor:has(#checkme:disabled) { color: blue } |
| .ancestor:has(#textinput:read-only) { color: skyblue } |
| .ancestor:has(#textinput:placeholder-shown) { color: navy } |
| .ancestor:has(#radioinput:default) { color: lightblue } |
| .ancestor:has(#textinput:valid) { color: lightgreen } |
| .ancestor:has(#numberinput:out-of-range) { color: darkgreen } |
| .ancestor:has(#numberinput:required) { color: pink } |
| .ancestor:has(#progress:indeterminate) { color: orange } |
| </style> |
| <div id=subject class=ancestor> |
| <input type="checkbox" name="my-checkbox" id="checkme"> |
| <label for="checkme">Check me!</label> |
| <input type="text" id="textinput" required> |
| <input id="radioinput" checked> |
| <input id="numberinput" type="number" min="1" max="10" value="5"> |
| <progress id="progress" value="50" max="100"></progress> |
| </div> |
| <script> |
| test(function() { |
| this.add_cleanup(() => { |
| checkme.checked = false; |
| }); |
| checkme.checked = false; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| checkme.checked = true; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 128, 0)", |
| "ancestor should be green"); |
| checkme.indeterminate = true; |
| assert_equals(getComputedStyle(subject).color, "rgb(154, 205, 50)", |
| "ancestor should be yellowgreen"); |
| const input = checkme; |
| checkme.remove(); |
| input.indeterminate = false; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| |
| subject.prepend(input); |
| checkme.checked = true; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 128, 0)", |
| "ancestor should be green"); |
| }, ":checked & :indeterminate invalidation on <input>"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| progress.setAttribute("value", "50"); |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| progress.removeAttribute("value"); |
| assert_equals(getComputedStyle(subject).color, "rgb(255, 165, 0)", |
| "ancestor should be orange"); |
| }, ":indeterminate invalidation on <progress>"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| checkme.disabled = false; |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| checkme.disabled = true; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 255)", |
| "ancestor should be blue"); |
| }, ":disabled invalidation"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| textinput.readOnly = false; |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| textinput.readOnly = true; |
| assert_equals(getComputedStyle(subject).color, "rgb(135, 206, 235)", |
| "ancestor should be skyblue"); |
| }, ":read-only invalidation"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| textinput.value = ""; |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| textinput.value = "text input"; |
| assert_equals(getComputedStyle(subject).color, "rgb(144, 238, 144)", |
| "ancestor should be lightgreen"); |
| }, ":valid invalidation"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| radioinput.removeAttribute("type"); |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| radioinput.type = 'radio'; |
| assert_equals(getComputedStyle(subject).color, "rgb(173, 216, 230)", |
| "ancestor should be lightblue"); |
| }, ":default invalidation with input[type=radio]"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| numberinput.required = false; |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| numberinput.required = true; |
| assert_equals(getComputedStyle(subject).color, "rgb(255, 192, 203)", |
| "ancestor should be pink"); |
| }, ":required invalidation"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| numberinput.value = 5; |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| numberinput.value = 12; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 100, 0)", |
| "ancestor should be darkgreen"); |
| }, ":out-of-range invalidation"); |
| |
| test(function() { |
| this.add_cleanup(() => { |
| textinput.removeAttribute("placeholder"); |
| }); |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", |
| "ancestor should be black"); |
| textinput.placeholder = 'placeholder text'; |
| assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 128)", |
| "ancestor should be navy"); |
| }, ":placeholder-shown invalidation"); |
| </script> |