Bug 1409083 Part 5: Add tests of new Flex API. draft
authorBrad Werth <bwerth@mozilla.com>
Wed, 01 Nov 2017 15:53:41 -0700
changeset 710144 51a51a6d32ab77523561c9fad8f67cf08e8da205
parent 710143 8b60a2affbebd423a356dca7782ec0685e2ed540
child 710247 40994663a949a9d19fd538f06722cfedf1835b52
push id92753
push userbwerth@mozilla.com
push dateFri, 08 Dec 2017 18:49:19 +0000
bugs1409083
milestone59.0a1
Bug 1409083 Part 5: Add tests of new Flex API. MozReview-Commit-ID: KWzThXA9Jk5
.eslintignore
dom/flex/moz.build
dom/flex/test/chrome.ini
dom/flex/test/chrome/test_flex_items.html
dom/flex/test/chrome/test_flex_lines.html
--- a/.eslintignore
+++ b/.eslintignore
@@ -215,16 +215,17 @@ dom/console/**
 dom/crypto/**
 dom/devicestorage/**
 dom/encoding/**
 dom/events/**
 dom/fetch/**
 dom/file/**
 dom/filehandle/**
 dom/filesystem/**
+dom/flex/**
 dom/flyweb/**
 dom/gamepad/**
 dom/geolocation/**
 dom/grid/**
 dom/html/**
 dom/imptests/**
 dom/interfaces/**
 dom/ipc/**
--- a/dom/flex/moz.build
+++ b/dom/flex/moz.build
@@ -2,16 +2,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
 
+MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
+
 EXPORTS.mozilla.dom += [
     'Flex.h',
     'FlexItem.h',
     'FlexLine.h',
 ]
 
 UNIFIED_SOURCES += [
     'Flex.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/flex/test/chrome.ini
@@ -0,0 +1,2 @@
+[chrome/test_flex_items.html]
+[chrome/test_flex_lines.html]
new file mode 100644
--- /dev/null
+++ b/dom/flex/test/chrome/test_flex_items.html
@@ -0,0 +1,169 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+  .container {
+    display: flex;
+    background-color: grey;
+    font: 14px sans-serif;
+    width: 800px;
+    height: 50px;
+  }
+
+  .base        { align-self: baseline; }
+  .lastbase    { align-self: last baseline; }
+
+  .offset      { margin-top: 10px;
+                 margin-bottom: 3px; }
+
+  .lime        { background: lime;   }
+  .yellow      { background: yellow; }
+  .orange      { background: orange; }
+  .pink        { background: pink;   }
+  .white       { background: white;  }
+
+  .crossMinMax { min-height: 40px;
+                 max-height: 120px; }
+
+  .mainMinMax  { min-width: 120px;
+                 max-width: 500px; }
+
+  .flexGrow    { flex-grow: 1; }
+
+  #second	     { width: 100px; }
+</style>
+
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+const TEXT_NODE = Ci.nsIDOMNode.TEXT_NODE;
+
+function testItemMatchesExpectedValues(item, values, index) {
+  if (typeof(values.node) != "undefined") {
+    is(item.node, values.node, "Item index " + index + " has expected node.");
+  }
+
+  if (typeof(values.node_todo) != "undefined") {
+    todo_is(item.node, values.node_todo, "Item index " + index + " has expected node.");
+  }
+
+  if (typeof(values.mainBaseSize) != "undefined") {
+    is(item.mainBaseSize, values.mainBaseSize, "Item index " + index + " has expected mainBaseSize.");
+  }
+
+  if (typeof(values.mainDeltaSize) != "undefined") {
+    is(item.mainDeltaSize, values.mainDeltaSize, "Item index " + index + " has expected mainDeltaSize.");
+  }
+
+  if (typeof(values.mainMinSize) != "undefined") {
+    is(item.mainMinSize, values.mainMinSize, "Item index " + index + " has expected mainMinSize.");
+  }
+
+  if (typeof(values.mainMaxSize) != "undefined") {
+    is(item.mainMaxSize, values.mainMaxSize, "Item index " + index + " has expected mainMaxSize.");
+  }
+
+  if (typeof(values.crossMinSize) != "undefined") {
+    is(item.crossMinSize, values.crossMinSize, "Item index " + index + " has expected crossMinSize.");
+  }
+
+  if (typeof(values.crossMaxSize) != "undefined") {
+    is(item.crossMaxSize, values.crossMaxSize, "Item index " + index + " has expected crossMaxSize.");
+  }
+}
+
+function nearlyEqual(a, b) {
+  const ep = 1e-4;
+  let diff = a - b;
+  return (diff < ep && diff > -ep);
+}
+
+function runTests() {
+  let container = document.getElementById("wrapper");
+  let flex = container.getAsFlexContainer();
+  let lines = flex.getLines();
+  is(lines.length, 1, "Container has expected number of lines.");
+
+  let line = lines[0];
+  let containerHeight = container.getBoundingClientRect().height;
+  is(line.crossSize, containerHeight, "Line crossSize equals the height of the container.");
+
+  let first = document.getElementById("first");
+  let second = document.getElementById("second");
+  let third = document.getElementById("third");
+  let fourth = document.getElementById("fourth");
+  let fifth = document.getElementById("fifth");
+  let sixth = container.lastChild;
+  is(sixth.nodeType, TEXT_NODE, "Sixth child should be an anonymous text node.");
+
+  // We can't compare baselines precisely, so we'll just confirm that they appear
+  // somewhere within the elements that determine them.
+  let firstRect = first.getBoundingClientRect();
+  ok(line.firstBaselineOffset > firstRect.top &&
+     line.firstBaselineOffset < firstRect.bottom,
+     "Line firstBaselineOffset lands somewhere within the element that determines it.");
+
+  // For last baseline, it's measured from the bottom, so we have to compare against
+  // the element bounds subtracted from the container height.
+  let secondRect = second.getBoundingClientRect();
+  ok(line.lastBaselineOffset > containerHeight - secondRect.bottom &&
+     line.lastBaselineOffset < containerHeight - secondRect.top,
+     "Line lastBaselineOffset lands somewhere within the element that determines it.");
+
+  let items = line.getItems();
+  is(items.length, 6, "Line has expected number of items.");
+
+  let expectedValues = [
+    { node: first,
+      crossMinSize: 0 },
+    { node: second,
+      mainBaseSize: secondRect.width,
+      mainDeltaSize: 0 },
+    { node: third,
+      crossMinSize: 40,
+      crossMaxSize: 120,
+      mainDeltaSize: 0 },
+    { node: fourth,
+      mainMinSize: 120,
+      mainMaxSize: 500,
+      mainDeltaSize: 0 },
+    { node: fifth,
+      mainDeltaSize: 0 },
+    { node: sixth },
+  ];
+
+  for (let i = 0; i < items.length; ++i) {
+    let item = items[i];
+    let values = expectedValues[i];
+    testItemMatchesExpectedValues(item, values, i);
+  }
+
+  // Check that the delta size of the first item is nearly equal to the actual size minus the base size.
+  ok(nearlyEqual(items[0].mainDeltaSize, firstRect.width - items[0].mainBaseSize),
+     "flex-grow item has expected mainDeltaSize.");
+
+  SimpleTest.finish();
+}
+</script>
+</head>
+
+<body onLoad="runTests();">
+  <div id="wrapper" class="container">
+    <div id="first" class="lime base flexGrow">one line (first)</div>
+    <div id="second" class="yellow lastbase">one line (last)</div>
+    <div id="third" class="orange offset lastbase crossMinMax">two<br/>lines and offset (last)</div>
+    <div id="fourth" class="pink offset base mainMinMax">offset (first)</div>
+    <div style="display:contents">
+      <div id="fifth" class="white">replaced</div>
+    </div>
+    anonymous text node
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/flex/test/chrome/test_flex_lines.html
@@ -0,0 +1,281 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+  f {
+    display: flex;
+    background-color: grey;
+    font: 12px sans-serif;
+    width: 800px;
+    height: 42px;
+    margin-bottom: 5px;
+  }
+
+  .withZ::after {
+    background-color: pink;
+    content: "Z";
+    width: 100px;
+    height: 10px;
+  }
+
+  .wrap {
+    flex-wrap: wrap;
+  }
+
+  .wrapReverse {
+    flex-wrap: wrap-reverse;
+  }
+
+  b {
+    background-color: gold;
+    min-width: 100px;
+    height: 20px;
+    flex-grow: 1;
+  }
+  b::after {
+    content: "B";
+  }
+
+  c {
+    background-color: yellow;
+    width: 200px;
+    height: 15px;
+  }
+  c::after {
+    content: "C";
+  }
+
+  d {
+    background-color: orange;
+    width: 300px;
+    height: 10px;
+  }
+  d::after {
+    content: "D";
+  }
+
+  e {
+    background-color: silver;
+    width: 300px;
+    height: 10px;
+    flex-shrink: 2;
+  }
+  e::after {
+    content: "E";
+  }
+</style>
+
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function testLineMatchesExpectedValues(line, values, lineIndex, flexIndex) {
+  if (typeof(values.growthState) != "undefined") {
+    is(line.growthState, values.growthState, "Flex index " + flexIndex + " line index " + lineIndex + " has expected growthState.");
+  }
+
+  if (typeof(values.crossSize) != "undefined") {
+    is(line.crossSize, values.crossSize, "Flex index " + flexIndex + " line index " + lineIndex + " has expected crossSize.");
+  }
+
+  if (typeof(values.itemCount) != "undefined") {
+    is(line.getItems().length, values.itemCount, "Flex index " + flexIndex + " line index " + lineIndex + " has expected number of items.");
+  }
+}
+
+function runTests() {
+  let expectedValues = [
+    // items don't fill container, no grow, shrink, or min-width
+    [{ crossSize: 42,
+       itemCount: 2,
+       growthState: "unchanged" }],
+    [{ crossSize: 42,
+       itemCount: 3,
+       growthState: "unchanged" }],
+
+    // items don't fill container, no grow, shrink, or min-width, with wrap and align-content:center -->
+    [{ crossSize: 15,
+       itemCount: 2,
+       growthState: "unchanged" }],
+    [{ crossSize: 15,
+       itemCount: 3,
+       growthState: "unchanged" }],
+
+    // items don't fill container, with grow
+    [{ crossSize: 42,
+       itemCount: 3,
+       growthState: "growing" }],
+    [{ crossSize: 42,
+       itemCount: 4,
+       growthState: "growing" }],
+
+    // items overfill container, with min-width, and sometimes with wrap
+    [{ crossSize: 42,
+       itemCount: 5,
+       growthState: "shrinking" }],
+    [{ crossSize: 21,
+       itemCount: 3,
+       growthState: "growing" },
+     { crossSize: 21,
+       itemCount: 2,
+       growthState: "growing" }],
+    [{ crossSize: 42,
+       itemCount: 6,
+       growthState: "shrinking" }],
+    [{ crossSize: 21,
+       itemCount: 3,
+       growthState: "growing" },
+     { crossSize: 21,
+       itemCount: 3,
+       growthState: "growing" }],
+
+    // items overfill container, with shrink and sometimes with wrap
+    [{ crossSize: 42,
+       itemCount: 3,
+       growthState: "shrinking" }],
+    [{ crossSize: 21,
+       itemCount: 2,
+       growthState: "unchanged" },
+     { crossSize: 21,
+       itemCount: 1,
+       growthState: "unchanged" }],
+    [{ crossSize: 42,
+       itemCount: 4,
+       growthState: "shrinking" }],
+    [{ crossSize: 21,
+       itemCount: 2,
+       growthState: "unchanged" },
+     { crossSize: 21,
+       itemCount: 2,
+       growthState: "unchanged" }],
+
+    // items overfill container, with wrap and different types of align-content
+    [{ crossSize: 26,
+       itemCount: 3 },
+     { crossSize: 16,
+       itemCount: 1 }],
+    [{ crossSize: 20,
+       itemCount: 3 },
+     { crossSize: 10,
+       itemCount: 1 }],
+    [{ crossSize: 20,
+       itemCount: 3 },
+     { crossSize: 10,
+       itemCount: 1 }],
+    [{ crossSize: 20,
+       itemCount: 3 },
+     { crossSize: 10,
+       itemCount: 1 }],
+    [{ crossSize: 20,
+       itemCount: 3 },
+     { crossSize: 10,
+       itemCount: 1 }],
+    [{ crossSize: 20,
+       itemCount: 3 },
+     { crossSize: 10,
+       itemCount: 1 }],
+
+    // items overfill container, with wrap-reverse and different types of align-content
+    [{ crossSize: 16,
+       itemCount: 2 },
+     { crossSize: 26,
+       itemCount: 3 }],
+    [{ crossSize: 10,
+       itemCount: 2 },
+     { crossSize: 20,
+       itemCount: 3 }],
+    [{ crossSize: 10,
+       itemCount: 2 },
+     { crossSize: 20,
+       itemCount: 3 }],
+    [{ crossSize: 10,
+       itemCount: 2 },
+     { crossSize: 20,
+       itemCount: 3 }],
+    [{ crossSize: 10,
+       itemCount: 2 },
+     { crossSize: 20,
+       itemCount: 3 }],
+    [{ crossSize: 10,
+       itemCount: 2 },
+     { crossSize: 20,
+       itemCount: 3 }],
+
+	// other strange types of flex containers
+    [{ itemCount: 3 }],
+  ];
+
+  let children = document.body.children;
+  is(children.length, expectedValues.length, "Document has expected number of flex containers.");
+
+  for (let i = 0; i < children.length; ++i) {
+    let flex = children.item(i).getAsFlexContainer();
+	ok(flex, "Document child index " + i + " is a flex container.");
+	if (flex) {
+	  let values = expectedValues[i];
+
+	  let lines = flex.getLines();
+	  is(lines.length, values.length, "Flex index " + i + " has expected number of lines.");
+
+      for (let j = 0; j < lines.length; ++j) {
+	    testLineMatchesExpectedValues(lines[j], values[j], j, i);
+	  }
+	}
+  }
+
+  SimpleTest.finish();
+}
+</script>
+</head>
+
+<body onLoad="runTests();">
+
+<!-- items don't fill container, no grow, shrink, or min-width -->
+<f><c></c><d></d></f>
+<f class="withZ"><c></c><d></d></f>
+
+<!-- items don't fill container, no grow, shrink, or min-width, with wrap and align-content:center -->
+<f class="wrap" style="align-content:center"><c></c><d></d></f>
+<f class="withZ wrap" style="align-content:center"><c></c><d></d></f>
+
+<!-- items don't fill container, with grow -->
+<f><b></b><c></c><d></d></f>
+<f class="withZ"><b></b><c></c><d></d></f>
+
+<!-- items overfill container, with min-width, and sometimes with wrap -->
+<f><b></b><d></d><d></d><d></d><b></b></f>
+<f class="wrap"><b></b><d></d><d></d><d></d><b></b></f>
+<f class="withZ"><b></b><d></d><d></d><d></d><b></b></f>
+<f class="wrap withZ"><b></b><d></d><d></d><d></d><b></b></f>
+
+<!-- items overfill container, with shrink and sometimes with wrap -->
+<f><d></d><d></d><e></e></f>
+<f class="wrap"><d></d><d></d><e></e></f>
+<f class="withZ"><d></d><d></d><e></e></f>
+<f class="wrap withZ"><d></d><d></d><e></e></f>
+
+<!-- items overfill container, with wrap and different types of align-content -->
+<f class="wrap"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:flex-start"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:flex-end"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:center"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:space-between"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:space-around"><b></b><c></c><d></d><e></e></f>
+
+<!-- items overfill container, with wrap-reverse and different types of align-content -->
+<f class="wrapReverse withZ"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:flex-start"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:flex-end"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:center"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:space-between"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:space-around"><b></b><c></c><d></d><e></e></f>
+
+<!-- other strange types of flex containers -->
+<f style="overflow:scroll"><d></d><d></d><e></e></f>
+
+</body>
+</html>