Bug 1545296 - Add regression test for click event suppression for the Picture-in-Picture toggle. r=dthayer
authorMike Conley <mconley@mozilla.com>
Tue, 07 May 2019 19:41:07 +0000
changeset 472965 52b85c93b0874349df4b6766c9915d4b8f993af0
parent 472964 7a987cb301d52b6207de900e91973d16ffa2f086
child 472966 f779706e1c536eed14906c93b34d91b4876b85fa
push id84942
push usermconley@mozilla.com
push dateTue, 07 May 2019 20:10:55 +0000
treeherderautoland@550a15442d5b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdthayer
bugs1545296
milestone68.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 1545296 - Add regression test for click event suppression for the Picture-in-Picture toggle. r=dthayer Differential Revision: https://phabricator.services.mozilla.com/D29679
toolkit/components/pictureinpicture/tests/browser.ini
toolkit/components/pictureinpicture/tests/click-event-helper.js
toolkit/components/pictureinpicture/tests/head.js
toolkit/components/pictureinpicture/tests/test-button-overlay.html
toolkit/components/pictureinpicture/tests/test-opaque-overlay.html
toolkit/components/pictureinpicture/tests/test-page.html
toolkit/components/pictureinpicture/tests/test-transparent-overlay-1.html
toolkit/components/pictureinpicture/tests/test-transparent-overlay-2.html
--- a/toolkit/components/pictureinpicture/tests/browser.ini
+++ b/toolkit/components/pictureinpicture/tests/browser.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 support-files =
+  click-event-helper.js
   head.js
   test-button-overlay.html
   test-page.html
   test-opaque-overlay.html
   test-transparent-overlay-1.html
   test-transparent-overlay-2.html
   test-video.mp4
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/pictureinpicture/tests/click-event-helper.js
@@ -0,0 +1,32 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * This helper script is used to record mouse button events for
+ * Picture-in-Picture toggle click tests. Anytime the toggle is
+ * clicked, we expect none of the events to be fired. Otherwise,
+ * all events should be fired when clicking.
+ */
+
+let eventTypes = [
+  "pointerdown",
+  "mousedown",
+  "pointerup",
+  "mouseup",
+  "click",
+];
+
+for (let event of eventTypes) {
+  addEventListener(event, recordEvent, { capture: true });
+}
+
+let recordedEvents = [];
+function recordEvent(event) {
+  recordedEvents.push(event.type);
+}
+
+function getRecordedEvents() {
+  let result = recordedEvents.concat();
+  recordedEvents = [];
+  return result;
+}
--- a/toolkit/components/pictureinpicture/tests/head.js
+++ b/toolkit/components/pictureinpicture/tests/head.js
@@ -80,16 +80,35 @@ async function toggleOpacityReachesThres
       let opacity = parseFloat(this.content.getComputedStyle(toggle).opacity);
       return opacity >= opacityThreshold;
     }, `Toggle should have opacity >= ${opacityThreshold}`, 100, 100);
 
     ok(true, "Toggle reached target opacity.");
   });
 }
 
+async function assertSawMouseEvents(browser, isExpectingEvents) {
+  const MOUSE_BUTTON_EVENTS = [
+    "pointerdown",
+    "mousedown",
+    "pointerup",
+    "mouseup",
+    "click",
+  ];
+
+  let mouseEvents = await ContentTask.spawn(browser, null, async () => {
+    return this.content.wrappedJSObject.getRecordedEvents();
+  });
+
+  let expectedEvents = isExpectingEvents ? MOUSE_BUTTON_EVENTS
+                                         : [];
+  Assert.deepEqual(mouseEvents, expectedEvents,
+                   "Expected to get the right mouse events.");
+}
+
 /**
  * Test helper for the Picture-in-Picture toggle. Loads a page, and then
  * tests the provided video elements for the toggle both appearing and
  * opening the Picture-in-Picture window in the expected cases.
  *
  * @param {String} testURL The URL of the page with the <video> elements.
  * @param {Object} expectations An object with the following schema:
  *   <video-element-id>: {
@@ -126,17 +145,17 @@ async function testToggle(testURL, expec
 
     for (let videoID of videoIDs) {
       await SimpleTest.promiseFocus(browser);
       info(`Testing video with id: ${videoID}`);
 
       // For each video, make sure it's scrolled into view, and get the rect for
       // the toggle while we're at it.
       let args = { videoID, TOGGLE_ID };
-      let toggleClientRect = await ContentTask.spawn(browser, args, async args => {
+      let { toggleClientRect, controls } = await ContentTask.spawn(browser, args, async args => {
         let { videoID, TOGGLE_ID } = args;
         let video = content.document.getElementById(videoID);
         video.scrollIntoView({ behaviour: "instant" });
         let shadowRoot = video.openOrClosedShadowRoot;
         let toggle = shadowRoot.getElementById(TOGGLE_ID);
 
         if (!video.controls) {
           // For no-controls <video> elements, an IntersectionObserver is used
@@ -146,17 +165,25 @@ async function testToggle(testURL, expec
           // the video that we care about is being tracked.
           let {PictureInPictureToggleChild} =
             ChromeUtils.import("resource://gre/actors/PictureInPictureChild.jsm");
           await ContentTaskUtils.waitForCondition(() => {
             return PictureInPictureToggleChild.isTracking(video);
           }, "Waiting for PictureInPictureToggleChild to be tracking the video.", 100, 100);
         }
         let rect = toggle.getBoundingClientRect();
-        return { top: rect.top, right: rect.right, left: rect.left, bottom: rect.bottom };
+        return {
+          toggleClientRect: {
+            top: rect.top,
+            right: rect.right,
+            left: rect.left,
+            bottom: rect.bottom,
+          },
+          controls: video.controls,
+        };
       });
 
       // Hover the mouse over the video to reveal the toggle.
       await BrowserTestUtils.synthesizeMouseAtCenter(`#${videoID}`, {
         type: "mousemove",
       }, browser);
       await BrowserTestUtils.synthesizeMouseAtCenter(`#${videoID}`, {
         type: "mouseover",
@@ -179,27 +206,40 @@ async function testToggle(testURL, expec
 
       if (expectations[videoID].canToggle) {
         info("Clicking on toggle, and expecting a Picture-in-Picture window to open");
         let domWindowOpened = BrowserTestUtils.domWindowOpened(null);
         await BrowserTestUtils.synthesizeMouseAtPoint(toggleLeft, toggleTop, {}, browser);
         let win = await domWindowOpened;
         ok(win, "A Picture-in-Picture window opened.");
         await BrowserTestUtils.closeWindow(win);
+
+        // Make sure that clicking on the toggle resulted in no mouse button events
+        // being fired in content.
+        await assertSawMouseEvents(browser, false);
       } else {
         info("Clicking on toggle, and expecting no Picture-in-Picture window opens");
         await BrowserTestUtils.synthesizeMouseAtPoint(toggleLeft, toggleTop, {}, browser);
 
+        // For videos without the built-in controls, we expect that all mouse events
+        // should have fired - otherwise, the events are all suppressed.
+        await assertSawMouseEvents(browser, !controls);
+
         // The message to open the Picture-in-Picture window would normally be sent
         // immediately before this Promise resolved, so the window should have opened
         // by now if it was going to happen.
         for (let win of Services.wm.getEnumerator(WINDOW_TYPE)) {
           if (!win.closed) {
             ok(false, "Found a Picture-in-Picture window unexpectedly.");
             return;
           }
         }
 
         ok(true, "No Picture-in-Picture window found.");
       }
+
+      // Click on the very top-left pixel of the document and ensure that we
+      // see all of the mouse events for it.
+      await BrowserTestUtils.synthesizeMouseAtPoint(1, 1, {}, browser);
+      assertSawMouseEvents(browser, true);
     }
   });
 }
--- a/toolkit/components/pictureinpicture/tests/test-button-overlay.html
+++ b/toolkit/components/pictureinpicture/tests/test-button-overlay.html
@@ -1,13 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Picture-in-Picture test - transparent overlays - 1</title>
+  <script type="text/javascript" src="click-event-helper.js"></script>
 </head>
 <style>
   video {
     display: block;
   }
 
   .container {
     position: relative;
--- a/toolkit/components/pictureinpicture/tests/test-opaque-overlay.html
+++ b/toolkit/components/pictureinpicture/tests/test-opaque-overlay.html
@@ -1,13 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Picture-in-Picture test - transparent overlays - 1</title>
+  <script type="text/javascript" src="click-event-helper.js"></script>
 </head>
 <style>
   video {
     display: block;
   }
 
   .container {
     position: relative;
--- a/toolkit/components/pictureinpicture/tests/test-page.html
+++ b/toolkit/components/pictureinpicture/tests/test-page.html
@@ -1,13 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Picture-in-Picture tests</title>
+  <script type="text/javascript" src="click-event-helper.js"></script>
 </head>
 <style>
   video {
     display: block;
     border: 1px solid black;
   }
 </style>
 <body>
--- a/toolkit/components/pictureinpicture/tests/test-transparent-overlay-1.html
+++ b/toolkit/components/pictureinpicture/tests/test-transparent-overlay-1.html
@@ -1,13 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Picture-in-Picture test - transparent overlays - 1</title>
+  <script type="text/javascript" src="click-event-helper.js"></script>
 </head>
 <style>
   video {
     display: block;
   }
 
   .container {
     position: relative;
--- a/toolkit/components/pictureinpicture/tests/test-transparent-overlay-2.html
+++ b/toolkit/components/pictureinpicture/tests/test-transparent-overlay-2.html
@@ -1,13 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Picture-in-Picture test - transparent overlays - 1</title>
+  <script type="text/javascript" src="click-event-helper.js"></script>
 </head>
 <style>
   video {
     display: block;
   }
 
   .container {
     position: relative;