gecko-dev/layout/style/test/test_flexbox_reflow_counts.html
Daniel Holbert e45bd243c2 Bug 1652228: In test_flexbox_reflow_counts.html, don't bother pruning (nonexistent) children from 'content' node, and use consistent vars. r=TYLin
Before this patch, the test tries to remove all children from the 'content'
node except for one, as part of cleaning up. This is unnecessary, because none
of the subtests ever add any additional children to the 'content' element.
(It's also problematic because in late beta & release, 'content' is a special
variable name by default.)

While we're at it, this patch also makes us address the other nodes more
consistently, using the explicit variable declarations at the top of the
script section rather than their implicit ID-granted variable names.

Differential Revision: https://phabricator.services.mozilla.com/D83251
2020-07-13 22:59:03 +00:00

200 lines
6.2 KiB
HTML

<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1142686
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1142686</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
.flex {
display: flex;
}
#outerFlex {
border: 1px solid black;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1142686">Mozilla Bug 1142686</a>
<div id="display">
<div id="content">
<div class="flex" id="outerFlex">
<div class="flex" id="midFlex">
<div id="innerBlock">
</div>
</div>
</div>
</div>
</div>
<pre id="test">
<script type="application/javascript">
"use strict";
/** Test for Bug 1142686 **/
/**
* This test checks how many reflows are required, when we make a change inside
* a set of two nested flex containers, with various styles applied to
* the containers & innermost child. Some flex layout operations require two
* passes (which can cause exponential blowup). This test is intended to verify
* that certain configurations do *not* require two-pass layout, by comparing
* the reflow-count for a more-complex scenario against a less-complex scenario.
*
* We have two nested flex containers around an initially-empty block. For each
* measurement, we put some text in the block, and we see how many frame-reflow
* operations occur as a result.
*/
const gUtils = SpecialPowers.getDOMWindowUtils(window);
// The elements:
const gOuterFlex = document.getElementById("outerFlex");
const gMidFlex = document.getElementById("midFlex");
const gInnerBlock = document.getElementById("innerBlock");
// This cleanup helper-function removes all children from 'parent'
// except for 'childToPreserve' (if specified)
function removeChildrenExcept(parent, childToPreserve)
{
if (childToPreserve && childToPreserve.parentNode != parent) {
// This is just a sanity/integrity-check -- if this fails, it's probably a
// bug in this test rather than in the code. I'm not checking this via
// e.g. "is(childToPreserve.parentNode, parent)", because this *should*
// always pass, and each "pass" is not interesting here since it's a
// sanity-check. It's only interesting/noteworthy if it fails. So, to
// avoid bloating this test's passed-subtest-count & output, we only bother
// reporting on this in the case where something's wrong.
ok(false, "bug in test; 'childToPreserve' should be child of 'parent'");
}
// For simplicity, we just remove *all children* and then reappend
// childToPreserve as the sole child.
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
if (childToPreserve) {
parent.appendChild(childToPreserve);
}
}
// Appends 'childCount' new children to 'parent'
function addNChildren(parent, childCount)
{
for (let i = 0; i < childCount; i++) {
let newChild = document.createElement("div");
// Give the new child some text so it's got a nonzero content-size:
newChild.append("a");
parent.appendChild(newChild);
}
}
// Undoes whatever styling customizations and DOM insertions that a given
// testcase has done, to prepare for running the next testcase.
function cleanup()
{
gOuterFlex.style = gMidFlex.style = gInnerBlock.style = "";
removeChildrenExcept(gInnerBlock);
removeChildrenExcept(gMidFlex, gInnerBlock);
removeChildrenExcept(gOuterFlex, gMidFlex);
}
// Each testcase here has a label (used in test output), a function to set up
// the testcase, and (optionally) a function to set up the reference case.
let gTestcases = [
{
label : "border on flex items",
addTestStyle : function() {
gMidFlex.style.border = gInnerBlock.style.border = "3px solid black";
},
},
{
label : "padding on flex items",
addTestStyle : function() {
gMidFlex.style.padding = gInnerBlock.style.padding = "5px";
},
},
{
label : "margin on flex items",
addTestStyle : function() {
gMidFlex.style.margin = gInnerBlock.style.margin = "2px";
},
},
{
// When we make a change in one flex item, the number of reflows should not
// scale with its number of siblings (as long as those siblings' sizes
// aren't impacted by the change):
label : "additional flex items in outer flex container",
// Compare 5 bonus flex items vs. 1 bonus flex item:
addTestStyle : function() {
addNChildren(gOuterFlex, 5);
},
addReferenceStyle : function() {
addNChildren(gOuterFlex, 1);
},
},
{
// (As above, but now the bonus flex items are one step deeper in the tree,
// on the nested flex container rather than the outer one)
label : "additional flex items in nested flex container",
addTestStyle : function() {
addNChildren(gMidFlex, 5);
},
addReferenceStyle : function() {
addNChildren(gMidFlex, 1);
},
},
];
// Flush layout & return the global frame-reflow-count
function getReflowCount()
{
let unusedVal = gOuterFlex.offsetHeight; // flush layout
return gUtils.framesReflowed;
}
// This function adds some text inside of gInnerBlock, and returns the number
// of frames that need to be reflowed as a result.
function makeTweakAndCountReflows()
{
let beforeCount = getReflowCount();
gInnerBlock.appendChild(document.createTextNode("hello"));
let afterCount = getReflowCount();
let numReflows = afterCount - beforeCount;
if (numReflows <= 0) {
ok(false, "something's wrong -- we should've reflowed *something*");
}
return numReflows;
}
// Given a testcase (from gTestcases), this function verifies that the
// testcase scenario requires the same number of reflows as the reference
// scenario.
function runOneTest(aTestcase)
{
aTestcase.addTestStyle();
let numTestcaseReflows = makeTweakAndCountReflows();
cleanup();
if (aTestcase.addReferenceStyle) {
aTestcase.addReferenceStyle();
}
let numReferenceReflows = makeTweakAndCountReflows();
cleanup();
is(numTestcaseReflows, numReferenceReflows,
"Testcase & reference case should require same number of reflows" +
" (testcase label: '" + aTestcase.label + "')");
}
gTestcases.forEach(runOneTest);
</script>
</pre>
</body>
</html>