summaryrefslogtreecommitdiffstats
path: root/layout/style/test/test_flexbox_layout.html
blob: 49ee287aa2cb9dee06d5d7c8592a3e5205a221bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=666041
-->
<head>
  <meta charset="utf-8">
  <title>Test for Bug 666041</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="flexbox_layout_testcases.js"></script>
  <script type="text/javascript" src="property_database.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666041">Mozilla Bug 666041</a>
<div id="display">
  <div id="content">
  </div>
</div>
<pre id="test">
<script type="application/javascript">
"use strict";

/** Test for Bug 666041 **/

/* Flexbox Layout Tests
 * --------------------
 * This mochitest exercises our implementation of the flexbox layout algorithm
 * by creating a flex container, inserting some flexible children, and then
 * verifying that the computed width of those children is what we expect.
 *
 * See flexbox_layout_testcases.js for the actual testcases & testcase format.
 */

function getComputedStyleWrapper(elem, prop)
{
  return window.getComputedStyle(elem).getPropertyValue(prop);
}

function setPossiblyAliasedProperty(aElem, aPropertyName, aPropertyValue,
                                    aPropertyMapping)
{
  let actualPropertyName = (aPropertyName in aPropertyMapping ?
                            aPropertyMapping[aPropertyName] : aPropertyName);

  if (!gCSSProperties[actualPropertyName]) {
    ok(false, "Bug in test: property '" + actualPropertyName +
              "' doesn't exist in gCSSProperties");
  } else {
    let domPropertyName = gCSSProperties[actualPropertyName].domProp;
    aElem.style[domPropertyName] = aPropertyValue;
  }
}

// Helper function to strip "px" off the end of a string
// (so that we can compare two lengths using "isfuzzy()" with an epsilon)
function stripPx(aLengthInPx)
{
  let pxOffset = aLengthInPx.length - 2; // subtract off length of "px"

  // Sanity-check the arg:
  ok(pxOffset > 0 && aLengthInPx.substr(pxOffset) == "px",
     "expecting value with 'px' units");

  return aLengthInPx.substr(0, pxOffset);
}

// The main test function.
// aFlexboxTestcase is an entry from the list in flexbox_layout_testcases.js
function testFlexboxTestcase(aFlexboxTestcase, aFlexDirection, aPropertyMapping)
{
  let content = document.getElementById("content");

  // Create flex container
  let flexContainer = document.createElement("div");
  flexContainer.style.display = "flex";
  flexContainer.style.flexDirection = aFlexDirection;
  setPossiblyAliasedProperty(flexContainer, "_main-size",
                             gDefaultFlexContainerSize,
                             aPropertyMapping);

  // Apply testcase's customizations for flex container (if any).
  if (aFlexboxTestcase.container_properties) {
    for (let propName in aFlexboxTestcase.container_properties) {
      let propValue = aFlexboxTestcase.container_properties[propName];
      setPossiblyAliasedProperty(flexContainer, propName, propValue,
                                 aPropertyMapping);
    }
  }

  // Create & append flex items
  aFlexboxTestcase.items.forEach(function(aChildSpec) {
    // Create an element for our item
    let child = document.createElement("div");

    // Set all the specified properties on our item
    for (let propName in aChildSpec) {
      // aChildSpec[propName] is either a specified value,
      // or an array of [specifiedValue, computedValue]
      let specifiedValue = Array.isArray(aChildSpec[propName]) ?
        aChildSpec[propName][0] :
        aChildSpec[propName];

      // SANITY CHECK:
      if (Array.isArray(aChildSpec[propName])) {
        ok(aChildSpec[propName].length >= 2 &&
           aChildSpec[propName].length <= 3,
           "unexpected number of elements in array within child spec");
      }

      if (specifiedValue !== null) {
        setPossiblyAliasedProperty(child, propName, specifiedValue,
                                   aPropertyMapping);
      }
    }

    // Append the item to the flex container
    flexContainer.appendChild(child);
  });

  // Append the flex container
  content.appendChild(flexContainer);

  // NOW: Test the computed style on the flex items
  let child = flexContainer.firstChild;
  for (let i = 0; i < aFlexboxTestcase.items.length; i++) {
    if (!child) { // sanity
      ok(false, "should have created a child for each child-spec");
    }

    let childSpec = aFlexboxTestcase.items[i];
    for (let propName in childSpec) {
      if (Array.isArray(childSpec[propName])) {
        let expectedVal = childSpec[propName][1];
        let actualPropName = (propName in aPropertyMapping ?
                              aPropertyMapping[propName] : propName);
        let actualVal = getComputedStyleWrapper(child, actualPropName);
        let message = "computed value of '" + actualPropName +
                      "' should match expected";

        if (childSpec[propName].length > 2) {
          // 3rd entry in array is epsilon
          // Need to strip off "px" units in order to use epsilon:
          let actualValNoPx = stripPx(actualVal);
          let expectedValNoPx = stripPx(expectedVal);
          isfuzzy(actualValNoPx, expectedValNoPx,
                  childSpec[propName][2], message);
        } else {
          is(actualVal, expectedVal, message);
        }
      }
    }

    child = child.nextSibling;
  }

  // Clean up: drop the flex container.
  content.removeChild(flexContainer);
}

function main()
{
  gFlexboxTestcases.forEach(
    function(aTestcase) {
      testFlexboxTestcase(aTestcase, "",
                          gRowPropertyMapping);
      testFlexboxTestcase(aTestcase, "row",
                          gRowPropertyMapping);
      testFlexboxTestcase(aTestcase, "row-reverse",
                          gRowReversePropertyMapping);
      testFlexboxTestcase(aTestcase, "column",
                          gColumnPropertyMapping);
      testFlexboxTestcase(aTestcase, "column-reverse",
                          gColumnReversePropertyMapping);
    }
  );
}

main();

</script>
</pre>
</body>
</html>