check-layout-th.js (10265B)
1 (function() { 2 // Test is initiated from body.onload, so explicit done() call is required. 3 setup({ explicit_done: true }); 4 5 function checkSubtreeExpectedValues(t, parent, prefix) 6 { 7 var checkedLayout = checkExpectedValues(t, parent, prefix); 8 Array.prototype.forEach.call(parent.childNodes, function(node) { 9 checkedLayout |= checkSubtreeExpectedValues(t, node, prefix); 10 }); 11 return checkedLayout; 12 } 13 14 function checkAttribute(output, node, attribute) 15 { 16 var result = node.getAttribute && node.getAttribute(attribute); 17 output.checked |= !!result; 18 return result; 19 } 20 21 function assert_tolerance(actual, expected, message) 22 { 23 if (isNaN(expected) || isNaN(actual) || Math.abs(actual - expected) >= 1) { 24 assert_equals(actual, Number(expected), message); 25 } 26 } 27 28 function checkDataKeys(node) { 29 // The purpose of this list of data-* attributes is simply to ensure typos 30 // in tests are caught. It is therefore "ok" to add to this list for 31 // specific tests. 32 var validData = new Set([ 33 "data-anchor-polyfill", 34 "data-expected-width", 35 "data-expected-height", 36 "data-offset-x", 37 "data-offset-y", 38 "data-expected-client-width", 39 "data-expected-client-height", 40 "data-expected-scroll-width", 41 "data-expected-scroll-height", 42 "data-expected-bounding-client-rect-width", 43 "data-expected-bounding-client-rect-height", 44 "data-total-x", 45 "data-total-y", 46 "data-expected-display", 47 "data-expected-padding-top", 48 "data-expected-padding-bottom", 49 "data-expected-padding-left", 50 "data-expected-padding-right", 51 "data-expected-margin-top", 52 "data-expected-margin-bottom", 53 "data-expected-margin-left", 54 "data-expected-margin-right" 55 ]); 56 if (!node || !node.getAttributeNames) 57 return; 58 // Use "data-test" prefix if you need custom-named data elements. 59 for (let name of node.getAttributeNames()) { 60 if (name.startsWith("data-") && !name.startsWith("data-test")) 61 assert_true(validData.has(name), name + " is a valid data attribute"); 62 } 63 } 64 65 function checkExpectedValues(t, node, prefix) 66 { 67 checkDataKeys(node); 68 var output = { checked: false }; 69 70 var expectedWidth = checkAttribute(output, node, "data-expected-width"); 71 if (expectedWidth) { 72 assert_tolerance(node.offsetWidth, expectedWidth, prefix + "width"); 73 } 74 75 var expectedHeight = checkAttribute(output, node, "data-expected-height"); 76 if (expectedHeight) { 77 assert_tolerance(node.offsetHeight, expectedHeight, prefix + "height"); 78 } 79 80 var expectedOffset = checkAttribute(output, node, "data-offset-x"); 81 if (expectedOffset) { 82 assert_tolerance(node.offsetLeft, expectedOffset, prefix + "offsetLeft"); 83 } 84 85 var expectedOffset = checkAttribute(output, node, "data-offset-y"); 86 if (expectedOffset) { 87 assert_tolerance(node.offsetTop, expectedOffset, prefix + "offsetTop"); 88 } 89 90 var expectedWidth = checkAttribute(output, node, "data-expected-client-width"); 91 if (expectedWidth) { 92 assert_tolerance(node.clientWidth, expectedWidth, prefix + "clientWidth"); 93 } 94 95 var expectedHeight = checkAttribute(output, node, "data-expected-client-height"); 96 if (expectedHeight) { 97 assert_tolerance(node.clientHeight, expectedHeight, prefix + "clientHeight"); 98 } 99 100 var expectedWidth = checkAttribute(output, node, "data-expected-scroll-width"); 101 if (expectedWidth) { 102 assert_tolerance(node.scrollWidth, expectedWidth, prefix + "scrollWidth"); 103 } 104 105 var expectedHeight = checkAttribute(output, node, "data-expected-scroll-height"); 106 if (expectedHeight) { 107 assert_tolerance(node.scrollHeight, expectedHeight, prefix + "scrollHeight"); 108 } 109 110 var expectedWidth = checkAttribute(output, node, "data-expected-bounding-client-rect-width"); 111 if (expectedWidth) { 112 assert_tolerance(node.getBoundingClientRect().width, expectedWidth, prefix + "getBoundingClientRect().width"); 113 } 114 115 var expectedHeight = checkAttribute(output, node, "data-expected-bounding-client-rect-height"); 116 if (expectedHeight) { 117 assert_tolerance(node.getBoundingClientRect().height, expectedHeight, prefix + "getBoundingClientRect().height"); 118 } 119 120 var expectedOffset = checkAttribute(output, node, "data-total-x"); 121 if (expectedOffset) { 122 var totalLeft = node.clientLeft + node.offsetLeft; 123 assert_tolerance(totalLeft, expectedOffset, prefix + 124 "clientLeft+offsetLeft (" + node.clientLeft + " + " + node.offsetLeft + ")"); 125 } 126 127 var expectedOffset = checkAttribute(output, node, "data-total-y"); 128 if (expectedOffset) { 129 var totalTop = node.clientTop + node.offsetTop; 130 assert_tolerance(totalTop, expectedOffset, prefix + 131 "clientTop+offsetTop (" + node.clientTop + " + " + node.offsetTop + ")"); 132 } 133 134 var expectedDisplay = checkAttribute(output, node, "data-expected-display"); 135 if (expectedDisplay) { 136 var actualDisplay = getComputedStyle(node).display; 137 assert_equals(actualDisplay, expectedDisplay, prefix + "display"); 138 } 139 140 var expectedPaddingTop = checkAttribute(output, node, "data-expected-padding-top"); 141 if (expectedPaddingTop) { 142 var actualPaddingTop = getComputedStyle(node).paddingTop; 143 // Trim the unit "px" from the output. 144 actualPaddingTop = actualPaddingTop.slice(0, -2); 145 assert_equals(actualPaddingTop, expectedPaddingTop, prefix + "padding-top"); 146 } 147 148 var expectedPaddingBottom = checkAttribute(output, node, "data-expected-padding-bottom"); 149 if (expectedPaddingBottom) { 150 var actualPaddingBottom = getComputedStyle(node).paddingBottom; 151 // Trim the unit "px" from the output. 152 actualPaddingBottom = actualPaddingBottom.slice(0, -2); 153 assert_equals(actualPaddingBottom, expectedPaddingBottom, prefix + "padding-bottom"); 154 } 155 156 var expectedPaddingLeft = checkAttribute(output, node, "data-expected-padding-left"); 157 if (expectedPaddingLeft) { 158 var actualPaddingLeft = getComputedStyle(node).paddingLeft; 159 // Trim the unit "px" from the output. 160 actualPaddingLeft = actualPaddingLeft.slice(0, -2); 161 assert_equals(actualPaddingLeft, expectedPaddingLeft, prefix + "padding-left"); 162 } 163 164 var expectedPaddingRight = checkAttribute(output, node, "data-expected-padding-right"); 165 if (expectedPaddingRight) { 166 var actualPaddingRight = getComputedStyle(node).paddingRight; 167 // Trim the unit "px" from the output. 168 actualPaddingRight = actualPaddingRight.slice(0, -2); 169 assert_equals(actualPaddingRight, expectedPaddingRight, prefix + "padding-right"); 170 } 171 172 var expectedMarginTop = checkAttribute(output, node, "data-expected-margin-top"); 173 if (expectedMarginTop) { 174 var actualMarginTop = getComputedStyle(node).marginTop; 175 // Trim the unit "px" from the output. 176 actualMarginTop = actualMarginTop.slice(0, -2); 177 assert_equals(actualMarginTop, expectedMarginTop, prefix + "margin-top"); 178 } 179 180 var expectedMarginBottom = checkAttribute(output, node, "data-expected-margin-bottom"); 181 if (expectedMarginBottom) { 182 var actualMarginBottom = getComputedStyle(node).marginBottom; 183 // Trim the unit "px" from the output. 184 actualMarginBottom = actualMarginBottom.slice(0, -2); 185 assert_equals(actualMarginBottom, expectedMarginBottom, prefix + "margin-bottom"); 186 } 187 188 var expectedMarginLeft = checkAttribute(output, node, "data-expected-margin-left"); 189 if (expectedMarginLeft) { 190 var actualMarginLeft = getComputedStyle(node).marginLeft; 191 // Trim the unit "px" from the output. 192 actualMarginLeft = actualMarginLeft.slice(0, -2); 193 assert_equals(actualMarginLeft, expectedMarginLeft, prefix + "margin-left"); 194 } 195 196 var expectedMarginRight = checkAttribute(output, node, "data-expected-margin-right"); 197 if (expectedMarginRight) { 198 var actualMarginRight = getComputedStyle(node).marginRight; 199 // Trim the unit "px" from the output. 200 actualMarginRight = actualMarginRight.slice(0, -2); 201 assert_equals(actualMarginRight, expectedMarginRight, prefix + "margin-right"); 202 } 203 204 return output.checked; 205 } 206 207 var testNumber = 0; 208 var highlightError = false; // displays outline around failed test element. 209 var printDomOnError = true; // prints dom when test fails. 210 211 window.checkLayout = function(selectorList, callDone = true) 212 { 213 if (!selectorList) { 214 console.error("You must provide a CSS selector of nodes to check."); 215 return; 216 } 217 var nodes = document.querySelectorAll(selectorList); 218 nodes = Array.prototype.slice.call(nodes); 219 var checkedLayout = false; 220 Array.prototype.forEach.call(nodes, function(node) { 221 const title = node.title ? `: ${node.title}` : ''; 222 test(function(t) { 223 var container = node.parentNode.className == 'container' ? node.parentNode : node; 224 var prefix = 225 printDomOnError ? '\n' + container.outerHTML + '\n' : ''; 226 var passed = false; 227 try { 228 checkedLayout |= checkExpectedValues(t, node.parentNode, prefix); 229 checkedLayout |= checkSubtreeExpectedValues(t, node, prefix); 230 passed = true; 231 } finally { 232 if (!passed && highlightError) { 233 if (!document.getElementById('testharness_error_css')) { 234 var style = document.createElement('style'); 235 style.id = 'testharness_error_css'; 236 style.textContent = '.testharness_error { outline: red dotted 2px !important; }'; 237 document.body.appendChild(style); 238 } 239 if (node) 240 node.classList.add('testharness_error'); 241 } 242 checkedLayout |= !passed; 243 } 244 }, `${selectorList} ${++testNumber}${title}`); 245 }); 246 if (!checkedLayout) { 247 console.error("No valid data-* attributes found in selector list : " + selectorList); 248 } 249 if (callDone) 250 done(); 251 }; 252 253 })();