2 testRunner.dumpAsText();
6 function insertAfter(nodeToAdd, referenceNode)
8 if (referenceNode == document.body) {
9 document.body.appendChild(nodeToAdd);
13 if (referenceNode.nextSibling)
14 referenceNode.parentNode.insertBefore(nodeToAdd, referenceNode.nextSibling);
16 referenceNode.parentNode.appendChild(nodeToAdd);
19 function checkSubtreeExpectedValues(parent, failures)
21 var checkedLayout = checkExpectedValues(parent, failures);
22 Array.prototype.forEach.call(parent.childNodes, function(node) {
23 checkedLayout |= checkSubtreeExpectedValues(node, failures);
28 function checkAttribute(output, node, attribute)
30 var result = node.getAttribute && node.getAttribute(attribute);
31 output.checked |= !!result;
35 function checkExpectedValues(node, failures)
37 var output = { checked: false };
38 var expectedWidth = checkAttribute(output, node, "data-expected-width");
40 if (isNaN(expectedWidth) || Math.abs(node.offsetWidth - expectedWidth) >= 1)
41 failures.push("Expected " + expectedWidth + " for width, but got " + node.offsetWidth + ". ");
44 var expectedHeight = checkAttribute(output, node, "data-expected-height");
46 if (isNaN(expectedHeight) || Math.abs(node.offsetHeight - expectedHeight) >= 1)
47 failures.push("Expected " + expectedHeight + " for height, but got " + node.offsetHeight + ". ");
50 var expectedOffset = checkAttribute(output, node, "data-offset-x");
52 if (isNaN(expectedOffset) || Math.abs(node.offsetLeft - expectedOffset) >= 1)
53 failures.push("Expected " + expectedOffset + " for offsetLeft, but got " + node.offsetLeft + ". ");
56 var expectedOffset = checkAttribute(output, node, "data-offset-y");
58 if (isNaN(expectedOffset) || Math.abs(node.offsetTop - expectedOffset) >= 1)
59 failures.push("Expected " + expectedOffset + " for offsetTop, but got " + node.offsetTop + ". ");
62 var expectedWidth = checkAttribute(output, node, "data-expected-client-width");
64 if (isNaN(expectedWidth) || Math.abs(node.clientWidth - expectedWidth) >= 1)
65 failures.push("Expected " + expectedWidth + " for clientWidth, but got " + node.clientWidth + ". ");
68 var expectedHeight = checkAttribute(output, node, "data-expected-client-height");
70 if (isNaN(expectedHeight) || Math.abs(node.clientHeight - expectedHeight) >= 1)
71 failures.push("Expected " + expectedHeight + " for clientHeight, but got " + node.clientHeight + ". ");
74 var expectedWidth = checkAttribute(output, node, "data-expected-scroll-width");
76 if (isNaN(expectedWidth) || Math.abs(node.scrollWidth - expectedWidth) >= 1)
77 failures.push("Expected " + expectedWidth + " for scrollWidth, but got " + node.scrollWidth + ". ");
80 var expectedHeight = checkAttribute(output, node, "data-expected-scroll-height");
82 if (isNaN(expectedHeight) || Math.abs(node.scrollHeight - expectedHeight) >= 1)
83 failures.push("Expected " + expectedHeight + " for scrollHeight, but got " + node.scrollHeight + ". ");
86 var expectedOffset = checkAttribute(output, node, "data-total-x");
88 var totalLeft = node.clientLeft + node.offsetLeft;
89 if (isNaN(expectedOffset) || Math.abs(totalLeft - expectedOffset) >= 1)
90 failures.push("Expected " + expectedOffset + " for clientLeft+offsetLeft, but got " + totalLeft + ", clientLeft: " + node.clientLeft + ", offsetLeft: " + node.offsetLeft + ". ");
93 var expectedOffset = checkAttribute(output, node, "data-total-y");
95 var totalTop = node.clientTop + node.offsetTop;
96 if (isNaN(expectedOffset) || Math.abs(totalTop - expectedOffset) >= 1)
97 failures.push("Expected " + expectedOffset + " for clientTop+offsetTop, but got " + totalTop + ", clientTop: " + node.clientTop + ", + offsetTop: " + node.offsetTop + ". ");
100 var expectedDisplay = checkAttribute(output, node, "data-expected-display");
101 if (expectedDisplay) {
102 var actualDisplay = getComputedStyle(node).display;
103 if (actualDisplay != expectedDisplay)
104 failures.push("Expected " + expectedDisplay + " for display, but got " + actualDisplay + ". ");
107 var expectedPaddingTop = checkAttribute(output, node, "data-expected-padding-top");
108 if (expectedPaddingTop) {
109 var actualPaddingTop = getComputedStyle(node).paddingTop;
110 // Trim the unit "px" from the output.
111 actualPaddingTop = actualPaddingTop.substring(0, actualPaddingTop.length - 2);
112 if (actualPaddingTop != expectedPaddingTop)
113 failures.push("Expected " + expectedPaddingTop + " for padding-top, but got " + actualPaddingTop + ". ");
116 var expectedPaddingBottom = checkAttribute(output, node, "data-expected-padding-bottom");
117 if (expectedPaddingBottom) {
118 var actualPaddingBottom = getComputedStyle(node).paddingBottom;
119 // Trim the unit "px" from the output.
120 actualPaddingBottom = actualPaddingBottom.substring(0, actualPaddingBottom.length - 2);
121 if (actualPaddingBottom != expectedPaddingBottom)
122 failures.push("Expected " + expectedPaddingBottom + " for padding-bottom, but got " + actualPaddingBottom + ". ");
125 var expectedPaddingLeft = checkAttribute(output, node, "data-expected-padding-left");
126 if (expectedPaddingLeft) {
127 var actualPaddingLeft = getComputedStyle(node).paddingLeft;
128 // Trim the unit "px" from the output.
129 actualPaddingLeft = actualPaddingLeft.substring(0, actualPaddingLeft.length - 2);
130 if (actualPaddingLeft != expectedPaddingLeft)
131 failures.push("Expected " + expectedPaddingLeft + " for padding-left, but got " + actualPaddingLeft + ". ");
134 var expectedPaddingRight = checkAttribute(output, node, "data-expected-padding-right");
135 if (expectedPaddingRight) {
136 var actualPaddingRight = getComputedStyle(node).paddingRight;
137 // Trim the unit "px" from the output.
138 actualPaddingRight = actualPaddingRight.substring(0, actualPaddingRight.length - 2);
139 if (actualPaddingRight != expectedPaddingRight)
140 failures.push("Expected " + expectedPaddingRight + " for padding-right, but got " + actualPaddingRight + ". ");
143 var expectedMarginTop = checkAttribute(output, node, "data-expected-margin-top");
144 if (expectedMarginTop) {
145 var actualMarginTop = getComputedStyle(node).marginTop;
146 // Trim the unit "px" from the output.
147 actualMarginTop = actualMarginTop.substring(0, actualMarginTop.length - 2);
148 if (actualMarginTop != expectedMarginTop)
149 failures.push("Expected " + expectedMarginTop + " for margin-top, but got " + actualMarginTop + ". ");
152 var expectedMarginBottom = checkAttribute(output, node, "data-expected-margin-bottom");
153 if (expectedMarginBottom) {
154 var actualMarginBottom = getComputedStyle(node).marginBottom;
155 // Trim the unit "px" from the output.
156 actualMarginBottom = actualMarginBottom.substring(0, actualMarginBottom.length - 2);
157 if (actualMarginBottom != expectedMarginBottom)
158 failures.push("Expected " + expectedMarginBottom + " for margin-bottom, but got " + actualMarginBottom + ". ");
161 var expectedMarginLeft = checkAttribute(output, node, "data-expected-margin-left");
162 if (expectedMarginLeft) {
163 var actualMarginLeft = getComputedStyle(node).marginLeft;
164 // Trim the unit "px" from the output.
165 actualMarginLeft = actualMarginLeft.substring(0, actualMarginLeft.length - 2);
166 if (actualMarginLeft != expectedMarginLeft)
167 failures.push("Expected " + expectedMarginLeft + " for margin-left, but got " + actualMarginLeft + ". ");
170 var expectedMarginRight = checkAttribute(output, node, "data-expected-margin-right");
171 if (expectedMarginRight) {
172 var actualMarginRight = getComputedStyle(node).marginRight;
173 // Trim the unit "px" from the output.
174 actualMarginRight = actualMarginRight.substring(0, actualMarginRight.length - 2);
175 if (actualMarginRight != expectedMarginRight)
176 failures.push("Expected " + expectedMarginRight + " for margin-right, but got " + actualMarginRight + ". ");
179 return output.checked;
182 window.checkLayout = function(selectorList, outputContainer)
186 console.error("You must provide a CSS selector of nodes to check.");
189 var nodes = document.querySelectorAll(selectorList);
190 nodes = Array.prototype.slice.call(nodes);
192 var checkedLayout = false;
193 Array.prototype.forEach.call(nodes, function(node) {
195 checkedLayout |= checkExpectedValues(node.parentNode, failures);
196 checkedLayout |= checkSubtreeExpectedValues(node, failures);
198 var container = node.parentNode.className == 'container' ? node.parentNode : node;
200 var pre = document.createElement('pre');
201 if (failures.length) {
202 pre.className = 'FAIL';
205 pre.appendChild(document.createTextNode(failures.length ? "FAIL:\n" + failures.join('\n') + '\n\n' + container.outerHTML : "PASS"));
207 var referenceNode = container;
208 if (outputContainer) {
209 if (!outputContainer.lastChild) {
210 // Inserting a text node so we have something to insertAfter.
211 outputContainer.textContent = " ";
213 referenceNode = outputContainer.lastChild;
215 insertAfter(pre, referenceNode);
218 if (!checkedLayout) {
219 document.body.innerHTML = "FAIL: No valid data-* attributes found in selector list : " + selectorList;
223 var pre = document.querySelector('.FAIL');
225 setTimeout(function() { pre.previousSibling.scrollIntoView(); }, 0);