Bug 571294 - Part 2: Tests for new select event behaviour, r=ehsan
authorMichael Layzell <michael@thelayzells.com>
Thu, 13 Aug 2015 11:33:37 -0400
changeset 294815 41ffed8cc5d34e954a4c5c9bcd4371a4c84c2847
parent 294814 24515d221f0a98f7e63e3f31eb9650ffacbbe82a
child 294816 8853d35b1154f25259240308b83ae8d05359ab98
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs571294
milestone43.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 571294 - Part 2: Tests for new select event behaviour, r=ehsan
dom/tests/mochitest/general/frameSelectEvents.html
dom/tests/mochitest/general/mochitest.ini
dom/tests/mochitest/general/test_selectevents.html
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/frameSelectEvents.html
@@ -0,0 +1,235 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Testing Selection Events</title>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  </head>
+
+  <body>
+    <div id="normal">
+      <span id="inner">A bunch of text in a span inside of a div which should be selected</span>
+    </div>
+
+    <div id="ce" contenteditable>
+      This is a random block of text
+    </div>
+
+    <script>
+      // Call the testing methods from the parent window
+      var is = parent.is;
+      var ok = parent.ok;
+
+      // spin() spins the event loop for two cycles, giving time for
+      // selectionchange events to be fired, and handled by our listeners.
+      function spin() {
+        return new Promise(function(a) {
+          parent.SimpleTest.executeSoon(function() {
+            parent.SimpleTest.executeSoon(a)
+          });
+        });
+      }
+
+      // The main test
+      parent.add_task(function *() {
+        yield spin();
+
+        var selectstart = 0;
+        var selectionchange = 0;
+        var cancel = false;
+        var selectstartTarget = null;
+
+        document.addEventListener('selectstart', function(aEvent) {
+          console.log("originaltarget", aEvent.originalTarget, "new", selectstartTarget);
+          is(aEvent.originalTarget, selectstartTarget,
+             "The original target of selectstart");
+          selectstartTarget = null;
+
+          console.log(selectstart);
+          selectstart++;
+
+          if (cancel) {
+            aEvent.preventDefault();
+          }
+        });
+        document.addEventListener('selectionchange', function(aEvent) {
+          is(aEvent.originalTarget, document,
+             "The original target of selectionchange should be the document");
+          console.log(selectionchange);
+          selectionchange++;
+        });
+
+        function elt(aId) { return document.getElementById(aId); }
+        function reset() { selectstart = 0; selectionchange = 0; cancel = false; }
+
+        function* mouseAction(aElement, aOffset, aType, aSelStart, aSelChng) {
+          if (aType == "click") { // You can simulate a click event by sending undefined
+            aType = undefined;
+          }
+          synthesizeMouse(aElement, aOffset, 10, { type: aType });
+          yield spin();
+          is(selectstart, aSelStart,
+             "SelStart Mouse Action (" + aOffset + " - " + aType + ")");
+          is(selectionchange, aSelChng,
+             "SelChng Mouse Action (" + aOffset + " - " + aType + ")");
+          reset();
+        }
+
+        function* keyAction(aKey, aShift, aAccel, aSelStart, aSelChng) {
+          synthesizeKey(aKey, { shiftKey: aShift, accelKey: aAccel });
+          yield spin();
+          is(selectstart, aSelStart,
+             "SelStart Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
+          is(selectionchange, aSelChng,
+             "SelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
+          reset();
+        }
+
+        var selection = document.getSelection();
+        function isCollapsed() { is(selection.isCollapsed, true, "Selection is collapsed"); }
+        function isNotCollapsed() { is(selection.isCollapsed, false, "Selection is not collapsed"); }
+
+        // Focus the contenteditable text
+        yield* mouseAction(elt("ce"), 100, "click", 0, 1);
+        isCollapsed();
+
+        // Move the selection to the right, this should only fire selectstart once
+        selectstartTarget = elt("ce").firstChild;
+        yield* keyAction("VK_RIGHT", true, false, 1, 1);
+        isNotCollapsed();
+        yield* keyAction("VK_RIGHT", true, false, 0, 1);
+        isNotCollapsed();
+
+        // Move it back so that the selection is empty again
+        yield* keyAction("VK_LEFT", true, false, 0, 1);
+        isNotCollapsed();
+        yield* keyAction("VK_LEFT", true, false, 0, 1);
+        isCollapsed();
+
+        // Going from empty to non-empty should fire selectstart again
+        selectstartTarget = elt("ce").firstChild;
+        yield* keyAction("VK_LEFT", true, false, 1, 1);
+        isNotCollapsed();
+
+        function* mouseMoves(aElement, aTarget) {
+          // Select a region
+          yield* mouseAction(aElement, 50, "mousedown", 0, 1);
+          isCollapsed();
+
+          selectstartTarget = aTarget;
+          yield* mouseAction(aElement, 100, "mousemove", 1, 1);
+          isNotCollapsed();
+
+          // Moving it more shouldn't trigger a start (move back to empty)
+          yield* mouseAction(aElement, 75, "mousemove", 0, 1);
+          isNotCollapsed();
+          yield* mouseAction(aElement, 50, "mousemove", 0, 1);
+          isCollapsed();
+
+          // Wiggling the mouse a little such that it doesn't select any
+          // characters shouldn't trigger a selection
+          yield* mouseAction(aElement, 49, "mousemove", 0, 0);
+          isCollapsed();
+
+          // Moving the mouse again from an empty selection should trigger a
+          // selectstart
+          selectstartTarget = aTarget;
+          yield* mouseAction(aElement, 25, "mousemove", 1, 1);
+          isNotCollapsed();
+
+          // Releasing the mouse shouldn't do anything
+          yield* mouseAction(aElement, 25, "mouseup", 0, 0);
+          isNotCollapsed();
+
+          // And neither should moving your mouse around when the mouse
+          // button isn't pressed
+          yield* mouseAction(aElement, 50, "mousemove", 0, 0);
+          isNotCollapsed();
+
+          // Clicking in an random location should move the selection, but not perform a
+          // selectstart
+          yield* mouseAction(aElement, 50, "click", 0, 1);
+          isCollapsed();
+
+          // Clicking there again should do nothing
+          yield* mouseAction(aElement, 50, "click", 0, 0);
+          isCollapsed();
+
+          // Selecting a region, and canceling the selectstart should mean that the
+          // selection remains collapsed
+          yield* mouseAction(aElement, 75, "mousedown", 0, 1);
+          isCollapsed();
+          cancel = true;
+          selectstartTarget = aTarget;
+          yield* mouseAction(aElement, 100, "mousemove", 1, 1);
+          isCollapsed();
+          yield* mouseAction(aElement, 100, "mouseup", 0, 0);
+          isCollapsed();
+        }
+
+        // Should work both on normal
+        yield* mouseMoves(elt("inner"), elt("inner").firstChild);
+        // and contenteditable fields
+        yield* mouseMoves(elt("ce"), elt("ce").firstChild);
+        // and fields with elements in them
+        yield* mouseMoves(elt("normal"), elt("inner").firstChild);
+
+        yield* mouseAction(elt("inner"), 50, "click", 0, 1);
+        isCollapsed();
+
+        reset();
+        // Select all should fire both selectstart and change
+        selectstartTarget = document.body;
+        yield* keyAction("A", false, true, 1, 1);
+        isNotCollapsed();
+
+        // Clear the selection
+        yield* mouseAction(elt("inner"), 50, "click", 0, 1);
+        isCollapsed();
+
+        // Even if we already have a selection
+        yield* mouseAction(elt("inner"), 75, "mousedown", 0, 1);
+        isCollapsed();
+        selectstartTarget = elt("inner").firstChild;
+        yield* mouseAction(elt("inner"), 100, "mousemove", 1, 1);
+        isNotCollapsed();
+        yield* mouseAction(elt("inner"), 100, "mouseup", 0, 0);
+        isNotCollapsed();
+
+        selectstartTarget = document.body;
+        yield* keyAction("A", false, true, 1, 1);
+        isNotCollapsed();
+
+        // Clear the selection
+        yield* mouseAction(elt("inner"), 50, "click", 0, 1);
+        isCollapsed();
+
+        // Make sure that a synthesized selection change doesn't fire selectstart
+        var s = document.getSelection();
+        s.removeAllRanges();
+        yield spin();
+        is(selectstart, 0, "Synthesized range removals shouldn't fire selectstart");
+        is(selectionchange, 1, "Synthesized range removals should change selectionchange");
+        reset();
+        isCollapsed();
+
+        var range = document.createRange();
+        range.selectNode(elt("inner"));
+        s.addRange(range);
+        yield spin();
+        is(selectstart, 0, "Synthesized range additions shouldn't fire selectstart");
+        is(selectionchange, 1, "Synthesized range additions should change selectionchange");
+        reset();
+        isNotCollapsed();
+
+        // Change the range, without replacing
+        range.selectNode(elt("ce"));
+        yield spin();
+        is(selectstart, 0, "Synthesized range mutations shouldn't fire selectstart");
+        is(selectionchange, 1, "Synthesized range mutations should change selectionchange");
+        reset();
+        isNotCollapsed();
+      });
+    </script>
+  </body>
+</html>
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -39,16 +39,17 @@ support-files =
   test_bug1012662_common.js
   frameStorageAllowed.html
   frameStoragePrevented.html
   frameStorageChrome.html
   frameStorageNullprincipal.sjs
   workerStorageAllowed.js
   workerStoragePrevented.js
   storagePermissionsUtils.js
+  frameSelectEvents.html
 
 [test_497898.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
 [test_bug504220.html]
 [test_bug628069_1.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug628069_2.html]
 [test_bug631440.html]
@@ -115,8 +116,10 @@ skip-if = buildapp == 'b2g' || buildapp 
 [test_storagePermissionsAccept.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsRejectForeign.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsReject.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsLimitForeign.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
+[test_selectevents.html]
+skip-if = buildapp == 'b2g' || buildapp == 'mulet' # Mouse doesn't select in the same way on b2g
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_selectevents.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Testing Selection Events</title>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  </head>
+
+  <body>
+    <iframe width="500"></iframe>
+    <script>
+      add_task(function* () {
+        // Push the correct preferences for the test
+        yield new Promise((done) => {
+          SpecialPowers.pushPrefEnv({'set': [['dom.select_events.enabled', true]]}, done);
+        });
+
+        // Start the actual test
+        yield new Promise((done) => {
+          var iframe = document.querySelector('iframe');
+          iframe.addEventListener('load', done);
+          iframe.setAttribute('src', 'frameSelectEvents.html');
+        });
+
+        // The child iframe will call add_task before we reach this point,
+        // and will handle the rest of the test.
+      });
+    </script>
+  </body>
+</html>