Bug 1586317 [wpt PR 19516] - Split operator-dictionary-001.html into smaller pieces to avoid timeo…, a=testonly
authorFrédéric Wang <fred.wang@free.fr>
Mon, 14 Oct 2019 13:37:40 +0000
changeset 559531 f1c972908486baa435dc045a386c43dcce1d9784
parent 559530 db5b60adab7b55af67b75f6f63066b4f500c1351
child 559532 e90b7dfb418b9f243e1fc75b9a36140f2eab314f
push id12177
push usercsabou@mozilla.com
push dateMon, 21 Oct 2019 14:52:16 +0000
treeherdermozilla-beta@1918a9cd33bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1586317, 19516
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1586317 [wpt PR 19516] - Split operator-dictionary-001.html into smaller pieces to avoid timeo…, a=testonly Automatic update from web-platform-tests Split operator-dictionary-001.html into smaller pieces to avoid timeout in debug modes. (#19516) -- wpt-commits: 128febdd882dfab454746abdb21aa03895691edb wpt-pr: 19516
testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-001.html
testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-002.html
testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-003.html
testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-004.html
testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-005.html
testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-006.html
testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.css
testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.js
--- a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-001.html
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-001.html
@@ -8,276 +8,24 @@
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
 <meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
 <meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/mathml/support/feature-detection.js"></script>
 <script src="/mathml/support/operator-dictionary.js"></script>
-<style>
-  @font-face {
-    font-family: operators;
-    src: url("/fonts/math/operators.woff");
-  }
-  math, math * {
-      font-family: operators;
-      /* Use large enough font-size so that 1/18em = 2.77px > epsilon and
-         one can really distinguish lspace/rspace values. */
-      font-size: 50px;
-  }
-</style>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
 <script>
   setup({ explicit_done: true });
   window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
-
   async function runTests() {
-      let epsilon = 1;
       let json = await fetchOperatorDictionary();
-
-      // The operator dictionary has more than one thousand of entries so the
-      // tests are grouped in chunks so that these don't get much more
-      // importance than other MathML tests. For easy debugging, one can set the
-      // chunk size to 1. Also, note that the test div will remain visible for
-      // failed tests.
-      const entryPerChunk = 50
-
-      var counter = 0;
-      var tests = {
-          "lspace/rspace": null,
-          "movablelimits": null,
-          "largeop": null,
-          "stretchy": null,
-          "symmetric": null,
-          "accent": null
-      };
-
-      for (key in json.dictionary) {
-
-          if (counter % entryPerChunk === 0) {
-              // Start of a new chunk.
-              // Complete current async tests and create new ones for the next chunk.
-              for (name in tests) {
-                  if (tests[name]) tests[name].done();
-                  tests[name] = async_test(`Operator dictionary chunk ${1 + counter / entryPerChunk} - ${name}`);
-              }
-          }
-
-          let parsedKey = splitKey(key);
-          let entry = json.dictionary[key];
-
-          tests["lspace/rspace"].step(function() {
-              assert_true(MathMLFeatureDetection.has_operator_spacing());
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mrow>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </mrow>\
-</math>\
- VS \
-<math>\
-  <mrow>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </mrow>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var mrows = div.getElementsByTagName("mrow");
-              function spaceBetween(element, i, j) {
-                  return element.children[j].getBoundingClientRect().left -
-                      element.children[i].getBoundingClientRect().right;
-              }
-              var lspace = spaceBetween(mrows[0], 0, 1);
-              var rspace = spaceBetween(mrows[0], 1, 2);
-              var lspaceRef = spaceBetween(mrows[1], 0, 1);
-              var rspaceRef = spaceBetween(mrows[1], 1, 2);
-              assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
-              assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
-              div.style.display = "none";
-          });
-
-          tests["movablelimits"].step(function() {
-              assert_true(MathMLFeatureDetection.has_movablelimits());
-              var defaultValue = defaultPropertyValue(entry, "movablelimits");
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <munder>\
-    <mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </munder>\
-</math>\
- VS \
-<math>\
-  <munder>\
-    <mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </munder>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var munders = div.getElementsByTagName("munder");
-              munder = munders[0].getBoundingClientRect()
-              munderRef = munders[1].getBoundingClientRect()
-              assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
-              div.style.display = "none";
-          });
-
-          tests["largeop"].step(function() {
-              // FIXME: Should really detect largeop support...
-              assert_true(MathMLFeatureDetection.has_mspace());
-              var defaultValue = defaultPropertyValue(entry, "largeop");
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-largeop for "${parsedKey.characters}" (${parsedKey.form}): \
-<math displaystyle="true">\
-  <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-</math>\
- VS \
-<math displaystyle="true">\
-  <mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var mos = div.getElementsByTagName("mo");
-              mo = mos[0].getBoundingClientRect()
-              moRef = mos[1].getBoundingClientRect()
-              assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
-              div.style.display = "none";
-          });
-
-          if (entry.horizontal) {
-              tests["stretchy"].step(function() {
-                  // FIXME: Should really detect stretchy support...
-                  assert_true(MathMLFeatureDetection.has_munder());
-                  var defaultValue = defaultPropertyValue(entry, "stretchy");
-                  document.body.insertAdjacentHTML("beforeend", `<div>\
-stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <munder>\
-    <mn>&nbsp;&nbsp;</mn>\
-    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-  </munder>\
-</math>\
- VS \
-<math>\
-  <munder>\
-    <mn>&nbsp;&nbsp;</mn>\
-    <mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
-  </munder>\
-</math>\
-</div>`);
-                  var div = document.body.lastElementChild;
-                  var mos = div.getElementsByTagName("mo");
-                  mo = mos[0].getBoundingClientRect()
-                  moRef = mos[1].getBoundingClientRect()
-                  assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
-                  div.style.display = "none";
-              });
-          } else {
-              tests["stretchy"].step(function() {
-                  // FIXME: Should really detect stretchy support...
-                  assert_true(MathMLFeatureDetection.has_mspace());
-                  var defaultValue = defaultPropertyValue(entry, "stretchy");
-                  document.body.insertAdjacentHTML("beforeend", `<div>\
-stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
-    <mspace height="2em"></mspace>\
-  </mrow>\
-</math>\
- VS \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
-    <mspace height="2em"></mspace>\
-  </mrow>\
-</math>\
-</div>`);
-                  var div = document.body.lastElementChild;
-                  var mos = div.getElementsByTagName("mo");
-                  mo = mos[0].getBoundingClientRect()
-                  moRef = mos[1].getBoundingClientRect()
-                  assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
-                  div.style.display = "none";
-              });
-              tests["symmetric"].step(function() {
-                  // FIXME: Should really detect symmetric support...
-                  assert_true(MathMLFeatureDetection.has_mspace());
-                  var defaultValue = defaultPropertyValue(entry, "symmetric");
-                  document.body.insertAdjacentHTML("beforeend", `<div>\
-symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
-    <mspace height="1.5em"></mspace>\
-  </mrow>\
-</math>\
- VS \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
-    <mspace height="1.5em"></mspace>\
-  </mrow>\
-</math>\
-</div>`);
-                  var div = document.body.lastElementChild;
-                  var mos = div.getElementsByTagName("mo");
-                  mo = mos[0].getBoundingClientRect()
-                  moRef = mos[1].getBoundingClientRect()
-                  assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
-                  div.style.display = "none";
-              });
-          }
-
-          tests["accent"].step(function() {
-              // FIXME: Should really detect accent support...
-              assert_true(MathMLFeatureDetection.has_mover());
-              var defaultValue = defaultPropertyValue(entry, "accent");
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-accent for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mover>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-  </mover>\
-</math>\
- VS \
-<math>\
-  <mover>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}" accent="${defaultValue}">${parsedKey.characters}</mo>\
-  </mover>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var movers = div.getElementsByTagName("mover");
-              function gapBetweenBaseAndScript(mover) {
-                  return mover.children[0].getBoundingClientRect().top -
-                      mover.children[1].getBoundingClientRect().bottom;
-              }
-              var gap = gapBetweenBaseAndScript(movers[0])
-              var gapRef = gapBetweenBaseAndScript(movers[1])
-              assert_approx_equals(gap, gapRef, epsilon, `Accent property for ${key} should be '${defaultValue}'`);
-              div.style.display = "none";
-          });
-
-          counter++;
-      }
-
-      // Complete current async tests.
-      for (name in tests) {
-          if (tests[name]) tests[name].done();
-      }
-
+      OperatorDictionaryTests.run(json, "lspace/rspace");
       done();
   }
 </script>
 </head>
 <body>
   <div id="log"></div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-002.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "movablelimits");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-003.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "largeop");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-004.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "stretchy");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-005.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "symmetric");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-006.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "accent");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.css
@@ -0,0 +1,10 @@
+@font-face {
+    font-family: operators;
+    src: url("/fonts/math/operators.woff");
+}
+math, math * {
+    font-family: operators;
+    /* Use large enough font-size so that 1/18em = 2.77px > epsilon and
+       one can really distinguish lspace/rspace values. */
+    font-size: 50px;
+}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.js
@@ -0,0 +1,256 @@
+var OperatorDictionaryTests = {
+    "lspace/rspace": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        assert_true(MathMLFeatureDetection.has_operator_spacing());
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </mrow>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var mrows = div.getElementsByTagName("mrow");
+        function spaceBetween(element, i, j) {
+            return element.children[j].getBoundingClientRect().left -
+                element.children[i].getBoundingClientRect().right;
+        }
+        var lspace = spaceBetween(mrows[0], 0, 1);
+        var rspace = spaceBetween(mrows[0], 1, 2);
+        var lspaceRef = spaceBetween(mrows[1], 0, 1);
+        var rspaceRef = spaceBetween(mrows[1], 1, 2);
+        assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
+        assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
+        div.style.display = "none";
+    },
+
+    "movablelimits": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        assert_true(MathMLFeatureDetection.has_movablelimits());
+        var defaultValue = defaultPropertyValue(entry, "movablelimits");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <munder>\
+    <mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </munder>\
+</math>\
+ VS \
+<math>\
+  <munder>\
+    <mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </munder>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var munders = div.getElementsByTagName("munder");
+        munder = munders[0].getBoundingClientRect()
+        munderRef = munders[1].getBoundingClientRect()
+        assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    "largeop": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        // FIXME: Should really detect largeop support...
+        assert_true(MathMLFeatureDetection.has_mspace());
+        var defaultValue = defaultPropertyValue(entry, "largeop");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+largeop for "${parsedKey.characters}" (${parsedKey.form}): \
+<math displaystyle="true">\
+  <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+</math>\
+ VS \
+<math displaystyle="true">\
+  <mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var mos = div.getElementsByTagName("mo");
+        mo = mos[0].getBoundingClientRect()
+        moRef = mos[1].getBoundingClientRect()
+        assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    "stretchy": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        if (entry.horizontal) {
+            // FIXME: Should really detect stretchy support...
+            assert_true(MathMLFeatureDetection.has_munder());
+            var defaultValue = defaultPropertyValue(entry, "stretchy");
+            document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <munder>\
+    <mn>&nbsp;&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+  </munder>\
+</math>\
+ VS \
+<math>\
+  <munder>\
+    <mn>&nbsp;&nbsp;</mn>\
+    <mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+  </munder>\
+</math>\
+</div>`);
+            var div = document.body.lastElementChild;
+            var mos = div.getElementsByTagName("mo");
+            mo = mos[0].getBoundingClientRect()
+            moRef = mos[1].getBoundingClientRect()
+            assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+            div.style.display = "none";
+        } else {
+            // FIXME: Should really detect stretchy support...
+            assert_true(MathMLFeatureDetection.has_mspace());
+            var defaultValue = defaultPropertyValue(entry, "stretchy");
+            document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
+    <mspace height="2em"></mspace>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+    <mspace height="2em"></mspace>\
+  </mrow>\
+</math>\
+</div>`);
+            var div = document.body.lastElementChild;
+            var mos = div.getElementsByTagName("mo");
+            mo = mos[0].getBoundingClientRect()
+            moRef = mos[1].getBoundingClientRect()
+            assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+            div.style.display = "none";
+        }
+    },
+
+    "symmetric": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        // FIXME: Should really detect symmetric support...
+        assert_true(MathMLFeatureDetection.has_mspace());
+        var defaultValue = defaultPropertyValue(entry, "symmetric");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
+    <mspace height="1.5em"></mspace>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
+    <mspace height="1.5em"></mspace>\
+  </mrow>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var mos = div.getElementsByTagName("mo");
+        mo = mos[0].getBoundingClientRect()
+        moRef = mos[1].getBoundingClientRect()
+        assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    "accent": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        // FIXME: Should really detect accent support...
+        assert_true(MathMLFeatureDetection.has_mover());
+        var defaultValue = defaultPropertyValue(entry, "accent");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+accent for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mover>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+  </mover>\
+</math>\
+ VS \
+<math>\
+  <mover>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}" accent="${defaultValue}">${parsedKey.characters}</mo>\
+  </mover>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var movers = div.getElementsByTagName("mover");
+        function gapBetweenBaseAndScript(mover) {
+            return mover.children[0].getBoundingClientRect().top -
+                mover.children[1].getBoundingClientRect().bottom;
+        }
+        var gap = gapBetweenBaseAndScript(movers[0])
+        var gapRef = gapBetweenBaseAndScript(movers[1])
+        assert_approx_equals(gap, gapRef, epsilon, `Accent property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    run: function(json, name) {
+        // The operator dictionary has more than one thousand of entries so the
+        // tests are grouped in chunks so that these don't get much more
+        // importance than other MathML tests. For easy debugging, one can set the
+        // chunk size to 1. Also, note that the test div will remain visible for
+        // failed tests.
+        const entryPerChunk = 50
+
+        var counter = 0;
+        var test;
+
+        for (key in json.dictionary) {
+
+            if (counter % entryPerChunk === 0) {
+                // Start of a new chunk.
+                // Complete current async tests and create new ones for the next chunk.
+                if (test) test.done();
+                test = async_test(`Operator dictionary chunk ${1 + counter / entryPerChunk} - ${name}`);
+            }
+
+            test.step(function() {
+                OperatorDictionaryTests[name](json, key);
+            });
+
+          counter++;
+        }
+
+        // Complete current async test.
+        if (test) test.done();
+    }
+};