Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / tests / browser / browser_test_swipe_gesture.js
blob0f456722060ca70b5ca83d23189aa70f1e063dbe
1 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* vim: set sts=2 sw=2 et tw=80: */
4 "use strict";
6 Services.scriptloader.loadSubScript(
7   "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js",
8   this
9 );
11 Services.scriptloader.loadSubScript(
12   "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js",
13   this
16 async function waitForWhile() {
17   await new Promise(resolve => {
18     requestIdleCallback(resolve, { timeout: 300 });
19   });
20   await new Promise(r => requestAnimationFrame(r));
23 requestLongerTimeout(2);
25 add_task(async () => {
26   // Set the default values for an OS that supports swipe to nav, except for
27   // pixel-size which varies by OS, we vary it in differente tests in this file.
28   await SpecialPowers.pushPrefEnv({
29     set: [
30       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
31       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
32       ["widget.disable-swipe-tracker", false],
33       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
34       // Set the velocity-contribution to 0 so we can exactly control the
35       // values in the swipe tracker via the delta in the events that we send.
36       ["widget.swipe.success-velocity-contribution", 0.0],
37       ["widget.swipe.pixel-size", 550.0],
38     ],
39   });
41   const firstPage = "about:about";
42   const secondPage = "about:mozilla";
43   const tab = await BrowserTestUtils.openNewForegroundTab(
44     gBrowser,
45     firstPage,
46     true /* waitForLoad */
47   );
49   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
50   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
52   // Make sure we can go back to the previous page.
53   ok(gBrowser.webNavigation.canGoBack);
54   // and we cannot go forward to the next page.
55   ok(!gBrowser.webNavigation.canGoForward);
57   let wheelEventCount = 0;
58   tab.linkedBrowser.addEventListener("wheel", () => {
59     wheelEventCount++;
60   });
62   // Send a pan that starts a navigate back but doesn't have enough delta to do
63   // anything. Don't send the pan end because we want to check the opacity
64   // before the MSD animation in SwipeTracker starts which can temporarily put
65   // us at 1 opacity.
66   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 0.9);
67   await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 0.9);
69   // Check both getComputedStyle instead of element.style.opacity because we use a transition on the opacity.
70   let computedOpacity = window
71     .getComputedStyle(gHistorySwipeAnimation._prevBox)
72     .getPropertyValue("opacity");
73   is(computedOpacity, "1", "opacity of prevbox is 1");
74   let opacity = gHistorySwipeAnimation._prevBox.style.opacity;
75   is(opacity, "", "opacity style isn't explicitly set");
77   const isTranslatingIcon =
78     Services.prefs.getIntPref(
79       "browser.swipe.navigation-icon-start-position",
80       0
81     ) != 0 ||
82     Services.prefs.getIntPref(
83       "browser.swipe.navigation-icon-end-position",
84       0
85     ) != 0;
86   if (isTranslatingIcon != 0) {
87     isnot(
88       window
89         .getComputedStyle(gHistorySwipeAnimation._prevBox)
90         .getPropertyValue("translate"),
91       "none",
92       "translate of prevbox is not `none` during gestures"
93     );
94   }
96   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 0.9);
98   // NOTE: We only get a wheel event for the beginPhase, rest of events have
99   // been captured by the swipe gesture module.
100   is(wheelEventCount, 1, "Received a wheel event");
102   await waitForWhile();
103   // Make sure any navigation didn't happen.
104   is(tab.linkedBrowser.currentURI.spec, secondPage);
106   // Try to navigate backward.
107   wheelEventCount = 0;
108   let startLoadingPromise = BrowserTestUtils.browserStarted(
109     tab.linkedBrowser,
110     firstPage
111   );
112   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
113     tab.linkedBrowser,
114     firstPage
115   );
116   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
117   // NOTE: We only get a wheel event for the beginPhase, rest of events have
118   // been captured by the swipe gesture module.
119   is(wheelEventCount, 1, "Received a wheel event");
121   // The element.style opacity will be 0 because we set it to 0 on successful navigation, however
122   // we have a tranisition on it so the computed style opacity will still be 1 because the transition hasn't started yet.
123   computedOpacity = window
124     .getComputedStyle(gHistorySwipeAnimation._prevBox)
125     .getPropertyValue("opacity");
126   Assert.equal(computedOpacity, 1, "computed opacity of prevbox is 1");
127   opacity = gHistorySwipeAnimation._prevBox.style.opacity;
128   Assert.equal(opacity, 0, "element.style opacity of prevbox 0");
130   if (isTranslatingIcon) {
131     // We don't have a transition for translate property so that we still have
132     // some amount of translate.
133     isnot(
134       window
135         .getComputedStyle(gHistorySwipeAnimation._prevBox)
136         .getPropertyValue("translate"),
137       "none",
138       "translate of prevbox is not `none` during the opacity transition"
139     );
140   }
142   // Make sure the gesture triggered going back to the previous page.
143   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
145   ok(gBrowser.webNavigation.canGoForward);
147   BrowserTestUtils.removeTab(tab);
148   await SpecialPowers.popPrefEnv();
151 // Same test as above but pixel-size is increased and the multipliers passed to panLeftToRight correspondingly increased.
152 add_task(async () => {
153   // Set the default values for an OS that supports swipe to nav, except for
154   // pixel-size which varies by OS, we vary it in differente tests
155   // in this file.
156   await SpecialPowers.pushPrefEnv({
157     set: [
158       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
159       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
160       ["widget.disable-swipe-tracker", false],
161       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
162       // Set the velocity-contribution to 0 so we can exactly control the
163       // values in the swipe tracker via the delta in the events that we send.
164       ["widget.swipe.success-velocity-contribution", 0.0],
165       ["widget.swipe.pixel-size", 1100.0],
166     ],
167   });
169   const firstPage = "about:about";
170   const secondPage = "about:mozilla";
171   const tab = await BrowserTestUtils.openNewForegroundTab(
172     gBrowser,
173     firstPage,
174     true /* waitForLoad */
175   );
177   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
178   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
180   // Make sure we can go back to the previous page.
181   ok(gBrowser.webNavigation.canGoBack);
182   // and we cannot go forward to the next page.
183   ok(!gBrowser.webNavigation.canGoForward);
185   let wheelEventCount = 0;
186   tab.linkedBrowser.addEventListener("wheel", () => {
187     wheelEventCount++;
188   });
190   // Send a pan that starts a navigate back but doesn't have enough delta to do
191   // anything. Don't send the pan end because we want to check the opacity
192   // before the MSD animation in SwipeTracker starts which can temporarily put
193   // us at 1 opacity.
194   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 1.8);
195   await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 1.8);
197   // Check both getComputedStyle instead of element.style.opacity because we use a transition on the opacity.
198   let computedOpacity = window
199     .getComputedStyle(gHistorySwipeAnimation._prevBox)
200     .getPropertyValue("opacity");
201   is(computedOpacity, "1", "opacity of prevbox is 1");
202   let opacity = gHistorySwipeAnimation._prevBox.style.opacity;
203   is(opacity, "", "opacity style isn't explicitly set");
205   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 1.8);
207   // NOTE: We only get a wheel event for the beginPhase, rest of events have
208   // been captured by the swipe gesture module.
209   is(wheelEventCount, 1, "Received a wheel event");
211   await waitForWhile();
212   // Make sure any navigation didn't happen.
213   is(tab.linkedBrowser.currentURI.spec, secondPage);
215   // Try to navigate backward.
216   wheelEventCount = 0;
217   let startLoadingPromise = BrowserTestUtils.browserStarted(
218     tab.linkedBrowser,
219     firstPage
220   );
221   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
222     tab.linkedBrowser,
223     firstPage
224   );
225   await panLeftToRight(tab.linkedBrowser, 100, 100, 2);
226   // NOTE: We only get a wheel event for the beginPhase, rest of events have
227   // been captured by the swipe gesture module.
228   is(wheelEventCount, 1, "Received a wheel event");
230   // The element.style opacity will be 0 because we set it to 0 on successful navigation, however
231   // we have a tranisition on it so the computed style opacity will still be 1 because the transition hasn't started yet.
232   computedOpacity = window
233     .getComputedStyle(gHistorySwipeAnimation._prevBox)
234     .getPropertyValue("opacity");
235   Assert.equal(computedOpacity, 1, "computed opacity of prevbox is 1");
236   opacity = gHistorySwipeAnimation._prevBox.style.opacity;
237   Assert.equal(opacity, 0, "element.style opacity of prevbox 0");
239   // Make sure the gesture triggered going back to the previous page.
240   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
242   ok(gBrowser.webNavigation.canGoForward);
244   BrowserTestUtils.removeTab(tab);
245   await SpecialPowers.popPrefEnv();
248 add_task(async () => {
249   // Set the default values for an OS that supports swipe to nav, except for
250   // pixel-size which varies by OS, we vary it in different tests
251   // in this file.
252   await SpecialPowers.pushPrefEnv({
253     set: [
254       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
255       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
256       ["widget.disable-swipe-tracker", false],
257       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
258       // Set the velocity-contribution to 1 (default 0.05f) so velocity is a
259       // large contribution to the success value in SwipeTracker.cpp so it
260       // pushes us into success territory without going into success territory
261       // purely from th deltas.
262       ["widget.swipe.success-velocity-contribution", 2.0],
263       ["widget.swipe.pixel-size", 550.0],
264     ],
265   });
267   async function runTest() {
268     const firstPage = "about:about";
269     const secondPage = "about:mozilla";
270     const tab = await BrowserTestUtils.openNewForegroundTab(
271       gBrowser,
272       firstPage,
273       true /* waitForLoad */
274     );
276     BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
277     await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
279     // Make sure we can go back to the previous page.
280     ok(gBrowser.webNavigation.canGoBack);
281     // and we cannot go forward to the next page.
282     ok(!gBrowser.webNavigation.canGoForward);
284     let wheelEventCount = 0;
285     tab.linkedBrowser.addEventListener("wheel", () => {
286       wheelEventCount++;
287     });
289     let startLoadingPromise = BrowserTestUtils.browserStarted(
290       tab.linkedBrowser,
291       firstPage
292     );
293     let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
294       tab.linkedBrowser,
295       firstPage
296     );
297     let startTime = performance.now();
298     await panLeftToRight(tab.linkedBrowser, 100, 100, 0.2);
299     let endTime = performance.now();
301     // If sending the events took too long then we might not have been able
302     // to generate enough velocity.
303     // The value 230 was picked based on try runs, in particular test verify
304     // runs on mac were the long pole, and when we get times near this we can
305     // still achieve the required velocity.
306     if (endTime - startTime > 230) {
307       BrowserTestUtils.removeTab(tab);
308       return false;
309     }
311     // NOTE: We only get a wheel event for the beginPhase, rest of events have
312     // been captured by the swipe gesture module.
313     is(wheelEventCount, 1, "Received a wheel event");
315     // The element.style opacity will be 0 because we set it to 0 on successful navigation, however
316     // we have a tranisition on it so the computed style opacity will still be 1 because the transition hasn't started yet.
317     let computedOpacity = window
318       .getComputedStyle(gHistorySwipeAnimation._prevBox)
319       .getPropertyValue("opacity");
320     Assert.equal(computedOpacity, 1, "computed opacity of prevbox is 1");
321     let opacity = gHistorySwipeAnimation._prevBox.style.opacity;
322     Assert.equal(opacity, 0, "element.style opacity of prevbox 0");
324     // Make sure the gesture triggered going back to the previous page.
325     await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
327     ok(gBrowser.webNavigation.canGoForward);
329     BrowserTestUtils.removeTab(tab);
331     return true;
332   }
334   let numTries = 15;
335   while (numTries > 0) {
336     await new Promise(r => requestAnimationFrame(r));
337     await new Promise(resolve => requestIdleCallback(resolve));
338     await new Promise(r => requestAnimationFrame(r));
340     // runTest return value indicates if test was able to run to the end.
341     if (await runTest()) {
342       break;
343     }
344     numTries--;
345   }
346   Assert.greater(numTries, 0, "never ran the test");
347   await SpecialPowers.popPrefEnv();
350 add_task(async () => {
351   // Set the default values for an OS that supports swipe to nav, except for
352   // pixel-size which varies by OS, we vary it in differente tests
353   // in this file.
354   await SpecialPowers.pushPrefEnv({
355     set: [
356       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
357       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
358       ["widget.disable-swipe-tracker", false],
359       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
360       // Set the velocity-contribution to 0 so we can exactly control the
361       // values in the swipe tracker via the delta in the events that we send.
362       ["widget.swipe.success-velocity-contribution", 0.0],
363       ["widget.swipe.pixel-size", 550.0],
364     ],
365   });
367   const firstPage = "about:about";
368   const secondPage = "about:mozilla";
369   const tab = await BrowserTestUtils.openNewForegroundTab(
370     gBrowser,
371     firstPage,
372     true /* waitForLoad */
373   );
375   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
376   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
378   // Make sure we can go back to the previous page.
379   ok(gBrowser.webNavigation.canGoBack);
380   // and we cannot go forward to the next page.
381   ok(!gBrowser.webNavigation.canGoForward);
383   let startLoadingPromise = BrowserTestUtils.browserStarted(
384     tab.linkedBrowser,
385     firstPage
386   );
387   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
388     tab.linkedBrowser,
389     firstPage
390   );
391   await panLeftToRight(tab.linkedBrowser, 100, 100, 2);
393   // Make sure the gesture triggered going back to the previous page.
394   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
396   ok(gBrowser.webNavigation.canGoForward);
398   while (
399     gHistorySwipeAnimation._prevBox != null ||
400     gHistorySwipeAnimation._nextBox != null
401   ) {
402     await new Promise(r => requestAnimationFrame(r));
403   }
405   ok(
406     gHistorySwipeAnimation._prevBox == null &&
407       gHistorySwipeAnimation._nextBox == null
408   );
410   BrowserTestUtils.removeTab(tab);
411   await SpecialPowers.popPrefEnv();
414 add_task(async () => {
415   await SpecialPowers.pushPrefEnv({
416     set: [
417       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
418       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
419       ["widget.disable-swipe-tracker", false],
420       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
421       // Set the velocity-contribution to 0 so we can exactly control the
422       // values in the swipe tracker via the delta in the events that we send.
423       ["widget.swipe.success-velocity-contribution", 0.0],
424       ["widget.swipe.pixel-size", 550.0],
425     ],
426   });
428   function swipeGestureEndPromise() {
429     return new Promise(resolve => {
430       let promiseObserver = {
431         handleEvent(aEvent) {
432           switch (aEvent.type) {
433             case "MozSwipeGestureEnd":
434               gBrowser.tabbox.removeEventListener(
435                 "MozSwipeGestureEnd",
436                 promiseObserver,
437                 true
438               );
439               resolve();
440               break;
441           }
442         },
443       };
444       gBrowser.tabbox.addEventListener(
445         "MozSwipeGestureEnd",
446         promiseObserver,
447         true
448       );
449     });
450   }
452   const firstPage = "about:about";
453   const secondPage = "about:mozilla";
454   const tab = await BrowserTestUtils.openNewForegroundTab(
455     gBrowser,
456     firstPage,
457     true /* waitForLoad */
458   );
460   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
461   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
463   // Make sure we can go back to the previous page.
464   ok(gBrowser.webNavigation.canGoBack);
465   // and we cannot go forward to the next page.
466   ok(!gBrowser.webNavigation.canGoForward);
468   let numSwipeGestureEndEvents = 0;
469   var anObserver = {
470     handleEvent(aEvent) {
471       switch (aEvent.type) {
472         case "MozSwipeGestureEnd":
473           numSwipeGestureEndEvents++;
474           break;
475       }
476     },
477   };
479   gBrowser.tabbox.addEventListener("MozSwipeGestureEnd", anObserver, true);
481   let gestureEndPromise = swipeGestureEndPromise();
483   is(
484     numSwipeGestureEndEvents,
485     0,
486     "expected no MozSwipeGestureEnd got " + numSwipeGestureEndEvents
487   );
489   // Send a pan that starts a navigate back but doesn't have enough delta to do
490   // anything.
491   await panLeftToRight(tab.linkedBrowser, 100, 100, 0.9);
493   await waitForWhile();
494   // Make sure any navigation didn't happen.
495   is(tab.linkedBrowser.currentURI.spec, secondPage);
496   // end event comes after a swipe that does not navigate
497   await gestureEndPromise;
498   is(
499     numSwipeGestureEndEvents,
500     1,
501     "expected one MozSwipeGestureEnd got " + numSwipeGestureEndEvents
502   );
504   // Try to navigate backward.
505   let startLoadingPromise = BrowserTestUtils.browserStarted(
506     tab.linkedBrowser,
507     firstPage
508   );
509   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
510     tab.linkedBrowser,
511     firstPage
512   );
514   gestureEndPromise = swipeGestureEndPromise();
516   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
518   // Make sure the gesture triggered going back to the previous page.
519   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
521   ok(gBrowser.webNavigation.canGoForward);
523   await gestureEndPromise;
525   is(
526     numSwipeGestureEndEvents,
527     2,
528     "expected one MozSwipeGestureEnd got " + (numSwipeGestureEndEvents - 1)
529   );
531   gBrowser.tabbox.removeEventListener("MozSwipeGestureEnd", anObserver, true);
533   BrowserTestUtils.removeTab(tab);
534   await SpecialPowers.popPrefEnv();
537 add_task(async () => {
538   // success-velocity-contribution is very high and pixel-size is
539   // very low so that one swipe goes over the threshold asap.
540   await SpecialPowers.pushPrefEnv({
541     set: [
542       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
543       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
544       ["widget.disable-swipe-tracker", false],
545       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
546       ["widget.swipe.success-velocity-contribution", 999999.0],
547       ["widget.swipe.pixel-size", 1.0],
548     ],
549   });
551   const firstPage = "about:about";
552   const secondPage = "about:mozilla";
553   const tab = await BrowserTestUtils.openNewForegroundTab(
554     gBrowser,
555     firstPage,
556     true /* waitForLoad */
557   );
559   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
560   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
562   // Make sure we can go back to the previous page.
563   ok(gBrowser.webNavigation.canGoBack);
564   // and we cannot go forward to the next page.
565   ok(!gBrowser.webNavigation.canGoForward);
567   // Navigate backward.
568   let startLoadingPromise = BrowserTestUtils.browserStarted(
569     tab.linkedBrowser,
570     firstPage
571   );
572   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
573     tab.linkedBrowser,
574     firstPage
575   );
577   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 100);
579   Assert.notEqual(gHistorySwipeAnimation._prevBox, null, "should have prevbox");
580   let transitionCancelPromise = new Promise(resolve => {
581     gHistorySwipeAnimation._prevBox.addEventListener(
582       "transitioncancel",
583       event => {
584         if (
585           event.propertyName == "opacity" &&
586           event.target == gHistorySwipeAnimation._prevBox
587         ) {
588           resolve();
589         }
590       },
591       { once: true }
592     );
593   });
594   let transitionStartPromise = new Promise(resolve => {
595     gHistorySwipeAnimation._prevBox.addEventListener(
596       "transitionstart",
597       event => {
598         if (
599           event.propertyName == "opacity" &&
600           event.target == gHistorySwipeAnimation._prevBox
601         ) {
602           resolve();
603         }
604       },
605       { once: true }
606     );
607   });
609   await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 100);
610   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 100);
612   // Make sure the gesture triggered going back to the previous page.
613   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
615   ok(gBrowser.webNavigation.canGoForward);
617   await Promise.any([transitionStartPromise, transitionCancelPromise]);
619   await TestUtils.waitForCondition(() => {
620     return (
621       gHistorySwipeAnimation._prevBox == null &&
622       gHistorySwipeAnimation._nextBox == null
623     );
624   });
626   // Navigate forward and check the forward navigation icon box state.
627   startLoadingPromise = BrowserTestUtils.browserStarted(
628     tab.linkedBrowser,
629     secondPage
630   );
631   stoppedLoadingPromise = BrowserTestUtils.browserStopped(
632     tab.linkedBrowser,
633     secondPage
634   );
636   await panRightToLeftBegin(tab.linkedBrowser, 100, 100, 100);
638   Assert.notEqual(gHistorySwipeAnimation._nextBox, null, "should have nextbox");
639   transitionCancelPromise = new Promise(resolve => {
640     gHistorySwipeAnimation._nextBox.addEventListener(
641       "transitioncancel",
642       event => {
643         if (
644           event.propertyName == "opacity" &&
645           event.target == gHistorySwipeAnimation._nextBox
646         ) {
647           resolve();
648         }
649       }
650     );
651   });
652   transitionStartPromise = new Promise(resolve => {
653     gHistorySwipeAnimation._nextBox.addEventListener(
654       "transitionstart",
655       event => {
656         if (
657           event.propertyName == "opacity" &&
658           event.target == gHistorySwipeAnimation._nextBox
659         ) {
660           resolve();
661         }
662       }
663     );
664   });
666   await panRightToLeftUpdate(tab.linkedBrowser, 100, 100, 100);
667   await panRightToLeftEnd(tab.linkedBrowser, 100, 100, 100);
669   // Make sure the gesture triggered going forward to the next page.
670   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
672   ok(gBrowser.webNavigation.canGoBack);
674   await Promise.any([transitionStartPromise, transitionCancelPromise]);
676   await TestUtils.waitForCondition(() => {
677     return (
678       gHistorySwipeAnimation._nextBox == null &&
679       gHistorySwipeAnimation._prevBox == null
680     );
681   });
683   BrowserTestUtils.removeTab(tab);
684   await SpecialPowers.popPrefEnv();
687 // A simple test case on RTL.
688 add_task(async () => {
689   await SpecialPowers.pushPrefEnv({
690     set: [
691       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
692       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
693       ["widget.disable-swipe-tracker", false],
694       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
695       ["widget.swipe.success-velocity-contribution", 0.5],
696       ["intl.l10n.pseudo", "bidi"],
697     ],
698   });
700   const newWin = await BrowserTestUtils.openNewBrowserWindow();
702   const firstPage = "about:about";
703   const secondPage = "about:mozilla";
704   const tab = await BrowserTestUtils.openNewForegroundTab(
705     newWin.gBrowser,
706     firstPage,
707     true /* waitForLoad */
708   );
710   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
711   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
713   // Make sure we can go back to the previous page.
714   ok(newWin.gBrowser.webNavigation.canGoBack);
715   // and we cannot go forward to the next page.
716   ok(!newWin.gBrowser.webNavigation.canGoForward);
718   // Make sure that our gesture support stuff has been initialized in the new
719   // browser window.
720   await TestUtils.waitForCondition(() => {
721     return newWin.gHistorySwipeAnimation.active;
722   });
724   // Try to navigate backward.
725   let startLoadingPromise = BrowserTestUtils.browserStarted(
726     tab.linkedBrowser,
727     firstPage
728   );
729   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
730     tab.linkedBrowser,
731     firstPage
732   );
733   await panRightToLeft(tab.linkedBrowser, 100, 100, 1);
734   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
736   ok(newWin.gBrowser.webNavigation.canGoForward);
738   // Now try to navigate forward again.
739   startLoadingPromise = BrowserTestUtils.browserStarted(
740     tab.linkedBrowser,
741     secondPage
742   );
743   stoppedLoadingPromise = BrowserTestUtils.browserStopped(
744     tab.linkedBrowser,
745     secondPage
746   );
747   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
748   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
750   ok(newWin.gBrowser.webNavigation.canGoBack);
752   await BrowserTestUtils.closeWindow(newWin);
753   await SpecialPowers.popPrefEnv();
756 add_task(async () => {
757   await SpecialPowers.pushPrefEnv({
758     set: [
759       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
760       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
761       ["widget.disable-swipe-tracker", false],
762       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
763       ["widget.swipe.success-velocity-contribution", 0.5],
764       ["apz.overscroll.enabled", true],
765       ["apz.test.logging_enabled", true],
766     ],
767   });
769   const tab = await BrowserTestUtils.openNewForegroundTab(
770     gBrowser,
771     "about:about",
772     true /* waitForLoad */
773   );
775   const URL_ROOT = getRootDirectory(gTestPath).replace(
776     "chrome://mochitests/content/",
777     "http://mochi.test:8888/"
778   );
779   BrowserTestUtils.startLoadingURIString(
780     tab.linkedBrowser,
781     URL_ROOT + "helper_swipe_gesture.html"
782   );
783   await BrowserTestUtils.browserLoaded(
784     tab.linkedBrowser,
785     false /* includeSubFrames */,
786     URL_ROOT + "helper_swipe_gesture.html"
787   );
789   // Make sure we can go back to the previous page.
790   ok(gBrowser.webNavigation.canGoBack);
792   await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
793     // Set `overscroll-behavior-x: contain` and flush it.
794     content.document.documentElement.style.overscrollBehaviorX = "contain";
795     content.document.documentElement.getBoundingClientRect();
796     await content.wrappedJSObject.promiseApzFlushedRepaints();
797   });
799   // Start a pan gesture but keep touching.
800   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 2);
802   // Flush APZ pending requests to make sure the pan gesture has been processed.
803   await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
804     await content.wrappedJSObject.promiseApzFlushedRepaints();
805   });
807   const isOverscrolled = await SpecialPowers.spawn(
808     tab.linkedBrowser,
809     [],
810     () => {
811       const scrollId = SpecialPowers.DOMWindowUtils.getViewId(
812         content.document.scrollingElement
813       );
814       const data = SpecialPowers.DOMWindowUtils.getCompositorAPZTestData();
815       return data.additionalData.some(entry => {
816         return (
817           entry.key == scrollId &&
818           entry.value.split(",").includes("overscrolled")
819         );
820       });
821     }
822   );
824   ok(isOverscrolled, "The root scroller should have overscrolled");
826   // Finish the pan gesture.
827   await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 2);
828   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 2);
830   // And wait a while to give a chance to navigate.
831   await waitForWhile();
833   // Make sure any navigation didn't happen.
834   is(tab.linkedBrowser.currentURI.spec, URL_ROOT + "helper_swipe_gesture.html");
836   BrowserTestUtils.removeTab(tab);
837   await SpecialPowers.popPrefEnv();
840 // A test case to make sure the short circuit path for swipe-to-navigations in
841 // APZ works, i.e. cases where we know for sure that the target APZC for a given
842 // pan-start event isn't scrollable in the pan-start event direction.
843 add_task(async () => {
844   await SpecialPowers.pushPrefEnv({
845     set: [
846       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
847       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
848       ["widget.disable-swipe-tracker", false],
849       ["apz.overscroll.enabled", true],
850     ],
851   });
853   const tab = await BrowserTestUtils.openNewForegroundTab(
854     gBrowser,
855     "about:about",
856     true /* waitForLoad */
857   );
859   const URL_ROOT = getRootDirectory(gTestPath).replace(
860     "chrome://mochitests/content/",
861     "http://mochi.test:8888/"
862   );
863   BrowserTestUtils.startLoadingURIString(
864     tab.linkedBrowser,
865     URL_ROOT + "helper_swipe_gesture.html"
866   );
867   await BrowserTestUtils.browserLoaded(
868     tab.linkedBrowser,
869     false /* includeSubFrames */,
870     URL_ROOT + "helper_swipe_gesture.html"
871   );
873   // Make sure the content can allow both of overscrolling and
874   // swipe-to-navigations.
875   const overscrollBehaviorX = await SpecialPowers.spawn(
876     tab.linkedBrowser,
877     [],
878     () => {
879       return content.window.getComputedStyle(content.document.documentElement)
880         .overscrollBehaviorX;
881     }
882   );
883   is(overscrollBehaviorX, "auto");
885   // Make sure we can go back to the previous page.
886   ok(gBrowser.webNavigation.canGoBack);
888   // Start a pan gesture but keep touching.
889   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 2);
891   // The above pan event should invoke a SwipeGestureStart event immediately so
892   // that the swipe-to-navigation icon box should be uncollapsed to show it.
893   ok(!gHistorySwipeAnimation._prevBox.collapsed);
895   // Finish the pan gesture, i.e. sending a pan-end event, otherwise a new
896   // pan-start event in the next will also generate a pan-interrupt event which
897   // will break the test.
898   await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 2);
899   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 2);
901   BrowserTestUtils.removeTab(tab);
902   await SpecialPowers.popPrefEnv();
905 add_task(async () => {
906   await SpecialPowers.pushPrefEnv({
907     set: [
908       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
909       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
910       ["widget.disable-swipe-tracker", false],
911       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
912       ["widget.swipe.success-velocity-contribution", 0.5],
913       ["apz.overscroll.enabled", true],
914       ["apz.test.logging_enabled", true],
915     ],
916   });
918   const tab = await BrowserTestUtils.openNewForegroundTab(
919     gBrowser,
920     "about:about",
921     true /* waitForLoad */
922   );
924   const URL_ROOT = getRootDirectory(gTestPath).replace(
925     "chrome://mochitests/content/",
926     "http://mochi.test:8888/"
927   );
928   BrowserTestUtils.startLoadingURIString(
929     tab.linkedBrowser,
930     URL_ROOT + "helper_swipe_gesture.html"
931   );
932   await BrowserTestUtils.browserLoaded(
933     tab.linkedBrowser,
934     false /* includeSubFrames */,
935     URL_ROOT + "helper_swipe_gesture.html"
936   );
938   // Make sure we can go back to the previous page.
939   ok(gBrowser.webNavigation.canGoBack);
941   // Start a pan gesture but keep touching.
942   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 2);
944   // Flush APZ pending requests to make sure the pan gesture has been processed.
945   await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
946     await content.wrappedJSObject.promiseApzFlushedRepaints();
947   });
949   const isOverscrolled = await SpecialPowers.spawn(
950     tab.linkedBrowser,
951     [],
952     () => {
953       const scrollId = SpecialPowers.DOMWindowUtils.getViewId(
954         content.document.scrollingElement
955       );
956       const data = SpecialPowers.DOMWindowUtils.getCompositorAPZTestData();
957       return data.additionalData.some(entry => {
958         return entry.key == scrollId && entry.value.includes("overscrolled");
959       });
960     }
961   );
963   ok(!isOverscrolled, "The root scroller should not have overscrolled");
965   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 0);
967   BrowserTestUtils.removeTab(tab);
968   await SpecialPowers.popPrefEnv();
971 add_task(async () => {
972   await SpecialPowers.pushPrefEnv({
973     set: [
974       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
975       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
976       ["widget.disable-swipe-tracker", false],
977       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
978       ["widget.swipe.success-velocity-contribution", 0.5],
979     ],
980   });
982   // Load three pages and go to the second page so that it can be navigated
983   // to both back and forward.
984   const tab = await BrowserTestUtils.openNewForegroundTab(
985     gBrowser,
986     "about:about",
987     true /* waitForLoad */
988   );
990   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, "about:mozilla");
991   await BrowserTestUtils.browserLoaded(
992     tab.linkedBrowser,
993     false /* includeSubFrames */,
994     "about:mozilla"
995   );
997   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, "about:home");
998   await BrowserTestUtils.browserLoaded(
999     tab.linkedBrowser,
1000     false /* includeSubFrames */,
1001     "about:home"
1002   );
1004   gBrowser.goBack();
1005   await BrowserTestUtils.browserLoaded(
1006     tab.linkedBrowser,
1007     false /* includeSubFrames */,
1008     "about:mozilla"
1009   );
1011   // Make sure we can go back and go forward.
1012   ok(gBrowser.webNavigation.canGoBack);
1013   ok(gBrowser.webNavigation.canGoForward);
1015   // Start a history back pan gesture but keep touching.
1016   await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 1);
1018   ok(
1019     !gHistorySwipeAnimation._prevBox.collapsed,
1020     "The icon box for the previous navigation should NOT be collapsed"
1021   );
1022   ok(
1023     gHistorySwipeAnimation._nextBox.collapsed,
1024     "The icon box for the next navigation should be collapsed"
1025   );
1027   // Pan back to the opposite direction so that the gesture should be cancelled.
1028   // eslint-disable-next-line no-undef
1029   await NativePanHandler.promiseNativePanEvent(
1030     tab.linkedBrowser,
1031     100,
1032     100,
1033     // eslint-disable-next-line no-undef
1034     NativePanHandler.delta,
1035     0,
1036     // eslint-disable-next-line no-undef
1037     NativePanHandler.updatePhase
1038   );
1040   ok(
1041     gHistorySwipeAnimation._prevBox.collapsed,
1042     "The icon box for the previous navigation should be collapsed"
1043   );
1044   ok(
1045     gHistorySwipeAnimation._nextBox.collapsed,
1046     "The icon box for the next navigation should be collapsed"
1047   );
1049   await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 0);
1051   BrowserTestUtils.removeTab(tab);
1052   await SpecialPowers.popPrefEnv();
1055 add_task(async () => {
1056   await SpecialPowers.pushPrefEnv({
1057     set: [
1058       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
1059       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
1060       ["widget.disable-swipe-tracker", false],
1061       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
1062       ["widget.swipe.success-velocity-contribution", 0.5],
1063       ["apz.overscroll.enabled", true],
1064       ["apz.overscroll.damping", 5.0],
1065       ["apz.content_response_timeout", 0],
1066     ],
1067   });
1069   const tab = await BrowserTestUtils.openNewForegroundTab(
1070     gBrowser,
1071     "about:about",
1072     true /* waitForLoad */
1073   );
1075   const URL_ROOT = getRootDirectory(gTestPath).replace(
1076     "chrome://mochitests/content/",
1077     "http://mochi.test:8888/"
1078   );
1080   // Load a horizontal scrollable content.
1081   BrowserTestUtils.startLoadingURIString(
1082     tab.linkedBrowser,
1083     URL_ROOT + "helper_swipe_gesture.html"
1084   );
1085   await BrowserTestUtils.browserLoaded(
1086     tab.linkedBrowser,
1087     false /* includeSubFrames */,
1088     URL_ROOT + "helper_swipe_gesture.html"
1089   );
1091   // Make sure we can go back to the previous page.
1092   ok(gBrowser.webNavigation.canGoBack);
1094   // Shift the horizontal scroll position slightly to make the content
1095   // overscrollable.
1096   await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
1097     content.document.documentElement.scrollLeft = 1;
1098     content.document.documentElement.getBoundingClientRect();
1099     await content.wrappedJSObject.promiseApzFlushedRepaints();
1100   });
1102   // Swipe horizontally to overscroll.
1103   await panLeftToRight(tab.linkedBrowser, 1, 100, 1);
1105   // Swipe again over the overscroll gutter.
1106   await panLeftToRight(tab.linkedBrowser, 1, 100, 1);
1108   // Wait the overscroll gutter is restored.
1109   await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
1110     // For some reasons using functions in apz_test_native_event_utils.js
1111     // sometimes causes "TypeError content.wrappedJSObject.XXXX is not a
1112     // function" error, so we observe "APZ:TransformEnd" instead of using
1113     // promiseTransformEnd().
1114     await new Promise((resolve, reject) => {
1115       SpecialPowers.Services.obs.addObserver(function observer(
1116         subject,
1117         topic,
1118         data
1119       ) {
1120         try {
1121           SpecialPowers.Services.obs.removeObserver(observer, topic);
1122           resolve([subject, data]);
1123         } catch (ex) {
1124           SpecialPowers.Services.obs.removeObserver(observer, topic);
1125           reject(ex);
1126         }
1127       },
1128       "APZ:TransformEnd");
1129     });
1130   });
1132   // Set up an APZ aware event listener and...
1133   await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
1134     content.document.documentElement.addEventListener("wheel", () => {}, {
1135       passive: false,
1136     });
1137     await content.wrappedJSObject.promiseApzFlushedRepaints();
1138   });
1140   // Try to swipe back again without overscrolling to make sure swipe-navigation
1141   // works with the APZ aware event listener.
1142   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
1144   let startLoadingPromise = BrowserTestUtils.browserStarted(
1145     tab.linkedBrowser,
1146     "about:about"
1147   );
1148   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
1149     tab.linkedBrowser,
1150     "about:about"
1151   );
1153   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
1155   ok(gBrowser.webNavigation.canGoForward);
1157   BrowserTestUtils.removeTab(tab);
1158   await SpecialPowers.popPrefEnv();
1161 // NOTE: This test listens wheel events so that it causes an overscroll issue
1162 // (bug 1800022). To avoid the bug, we need to run this test case at the end
1163 // of this file.
1164 add_task(async () => {
1165   await SpecialPowers.pushPrefEnv({
1166     set: [
1167       ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"],
1168       ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"],
1169       ["widget.disable-swipe-tracker", false],
1170       ["widget.swipe.velocity-twitch-tolerance", 0.0000001],
1171       ["widget.swipe.success-velocity-contribution", 0.5],
1172     ],
1173   });
1175   const firstPage = "about:about";
1176   const secondPage = "about:mozilla";
1177   const tab = await BrowserTestUtils.openNewForegroundTab(
1178     gBrowser,
1179     firstPage,
1180     true /* waitForLoad */
1181   );
1183   BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, secondPage);
1184   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage);
1186   // Make sure we can go back to the previous page.
1187   ok(gBrowser.webNavigation.canGoBack);
1188   // and we cannot go forward to the next page.
1189   ok(!gBrowser.webNavigation.canGoForward);
1191   let wheelEventCount = 0;
1192   tab.linkedBrowser.addEventListener("wheel", () => {
1193     wheelEventCount++;
1194   });
1196   // Try to navigate forward.
1197   await panRightToLeft(tab.linkedBrowser, 100, 100, 1);
1198   // NOTE: The last endPhase shouldn't fire a wheel event since
1199   // its delta is zero.
1200   is(wheelEventCount, 2, "Received 2 wheel events");
1202   await waitForWhile();
1203   // Make sure any navigation didn't happen.
1204   is(tab.linkedBrowser.currentURI.spec, secondPage);
1206   // Try to navigate backward.
1207   wheelEventCount = 0;
1208   let startLoadingPromise = BrowserTestUtils.browserStarted(
1209     tab.linkedBrowser,
1210     firstPage
1211   );
1212   let stoppedLoadingPromise = BrowserTestUtils.browserStopped(
1213     tab.linkedBrowser,
1214     firstPage
1215   );
1216   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
1217   // NOTE: We only get a wheel event for the beginPhase, rest of events have
1218   // been captured by the swipe gesture module.
1219   is(wheelEventCount, 1, "Received a wheel event");
1221   // Make sure the gesture triggered going back to the previous page.
1222   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
1224   ok(gBrowser.webNavigation.canGoForward);
1226   // Now try to navigate forward again.
1227   wheelEventCount = 0;
1228   startLoadingPromise = BrowserTestUtils.browserStarted(
1229     tab.linkedBrowser,
1230     secondPage
1231   );
1232   stoppedLoadingPromise = BrowserTestUtils.browserStopped(
1233     tab.linkedBrowser,
1234     secondPage
1235   );
1236   await panRightToLeft(tab.linkedBrowser, 100, 100, 1);
1237   is(wheelEventCount, 1, "Received a wheel event");
1239   await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
1241   ok(gBrowser.webNavigation.canGoBack);
1243   // Now try to navigate backward again but with preventDefault-ed event
1244   // handler.
1245   wheelEventCount = 0;
1246   let wheelEventListener = event => {
1247     event.preventDefault();
1248   };
1249   tab.linkedBrowser.addEventListener("wheel", wheelEventListener);
1250   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
1251   is(wheelEventCount, 3, "Received all wheel events");
1253   await waitForWhile();
1254   // Make sure any navigation didn't happen.
1255   is(tab.linkedBrowser.currentURI.spec, secondPage);
1257   // Now drop the event handler and disable the swipe tracker and try to swipe
1258   // again.
1259   wheelEventCount = 0;
1260   tab.linkedBrowser.removeEventListener("wheel", wheelEventListener);
1261   await SpecialPowers.pushPrefEnv({
1262     set: [["widget.disable-swipe-tracker", true]],
1263   });
1265   await panLeftToRight(tab.linkedBrowser, 100, 100, 1);
1266   is(wheelEventCount, 3, "Received all wheel events");
1268   await waitForWhile();
1269   // Make sure any navigation didn't happen.
1270   is(tab.linkedBrowser.currentURI.spec, secondPage);
1272   BrowserTestUtils.removeTab(tab);
1273   await SpecialPowers.popPrefEnv();