From 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:47:29 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- .../components/pictureinpicture/tests/browser.ini | 155 +++ ...owser_aaa_run_first_firstTimePiPToggleEvents.js | 314 ++++++ .../tests/browser_aaa_telemetry_togglePiP.js | 69 ++ .../tests/browser_backgroundTab.js | 93 ++ .../tests/browser_cannotTriggerFromContent.js | 32 + .../tests/browser_changePiPSrcInFullscreen.js | 511 +++++++++ .../tests/browser_closePipPause.js | 68 ++ .../browser_closePip_pageNavigationChanges.js | 113 ++ .../pictureinpicture/tests/browser_closePlayer.js | 48 + .../pictureinpicture/tests/browser_closeTab.js | 25 + .../tests/browser_close_unpip_focus.js | 72 ++ .../tests/browser_conflictingPips.js | 46 + .../pictureinpicture/tests/browser_contextMenu.js | 238 +++++ .../tests/browser_controlsHover.js | 191 ++++ .../tests/browser_cornerSnapping.js | 271 +++++ .../tests/browser_dblclickFullscreen.js | 101 ++ .../tests/browser_durationChange.js | 61 ++ .../tests/browser_flipIconWithRTL.js | 66 ++ .../tests/browser_fontSize_change.js | 152 +++ .../pictureinpicture/tests/browser_fullscreen.js | 142 +++ .../tests/browser_improved_controls.js | 303 ++++++ .../tests/browser_keyboardClosePIPwithESC.js | 71 ++ .../tests/browser_keyboardFullScreenPIPShortcut.js | 41 + .../tests/browser_keyboardShortcut.js | 134 +++ .../tests/browser_keyboardShortcutClosePIP.js | 53 + .../browser_keyboardShortcutWithNanDuration.js | 54 + .../tests/browser_keyboardToggle.js | 32 + .../tests/browser_mediaStreamVideos.js | 59 ++ .../tests/browser_mouseButtonVariation.js | 97 ++ .../pictureinpicture/tests/browser_multiPip.js | 225 ++++ .../tests/browser_nimbusDisplayDuration.js | 214 ++++ .../tests/browser_nimbusFirstTimeStyleVariant.js | 118 +++ .../tests/browser_nimbusMessageFirstTimePip.js | 121 +++ .../tests/browser_nimbusShowIconOnly.js | 114 ++ .../browser_noPlayerControlsOnMiddleRightClick.js | 53 + .../tests/browser_noToggleOnAudio.js | 46 + .../tests/browser_occluded_window.js | 258 +++++ .../tests/browser_playerControls.js | 86 ++ .../tests/browser_preserveTabPipIconOverlay.js | 167 +++ .../tests/browser_privateWindow.js | 38 + .../tests/browser_removeVideoElement.js | 84 ++ .../pictureinpicture/tests/browser_resizeVideo.js | 293 ++++++ .../pictureinpicture/tests/browser_reversePiP.js | 145 +++ .../tests/browser_saveLastPiPLoc.js | 398 +++++++ .../tests/browser_shortcutsAfterFocus.js | 67 ++ .../pictureinpicture/tests/browser_showMessage.js | 29 + .../tests/browser_smallVideoLayout.js | 210 ++++ .../tests/browser_stripVideoStyles.js | 49 + .../tests/browser_subtitles_settings_panel.js | 273 +++++ .../tests/browser_tabIconOverlayPiP.js | 90 ++ .../tests/browser_telemetry_enhancements.js | 230 ++++ .../tests/browser_text_tracks_webvtt_1.js | 129 +++ .../tests/browser_text_tracks_webvtt_2.js | 444 ++++++++ .../tests/browser_text_tracks_webvtt_3.js | 218 ++++ .../tests/browser_thirdPartyIframe.js | 72 ++ .../tests/browser_toggleAfterTabTearOutIn.js | 58 + .../tests/browser_toggleButtonOnNanDuration.js | 32 + .../tests/browser_toggleButtonOverlay.js | 17 + .../pictureinpicture/tests/browser_toggleMode_2.js | 202 ++++ .../tests/browser_toggleOnInsertedVideo.js | 42 + .../tests/browser_toggleOpaqueOverlay.js | 16 + .../tests/browser_togglePointerEventsNone.js | 16 + .../tests/browser_togglePolicies.js | 127 +++ .../tests/browser_togglePositionChange.js | 58 + .../pictureinpicture/tests/browser_toggleSimple.js | 18 + .../tests/browser_toggleTransparentOverlay-1.js | 33 + .../tests/browser_toggleTransparentOverlay-2.js | 33 + .../tests/browser_toggle_enabled.js | 99 ++ .../tests/browser_toggle_videocontrols.js | 76 ++ .../tests/browser_toggle_without_audio.js | 71 ++ .../tests/browser_touch_toggle_enablepip.js | 217 ++++ .../tests/browser_urlbar_toggle.js | 329 ++++++ .../pictureinpicture/tests/browser_videoEmptied.js | 155 +++ .../tests/browser_videoSelection.js | 106 ++ .../pictureinpicture/tests/click-event-helper.js | 26 + toolkit/components/pictureinpicture/tests/head.js | 1110 ++++++++++++++++++++ .../pictureinpicture/tests/no-audio-track.webm | Bin 0 -> 215529 bytes .../components/pictureinpicture/tests/short.mp4 | Bin 0 -> 38713 bytes .../tests/test-button-overlay.html | 81 ++ .../pictureinpicture/tests/test-media-stream.html | 25 + .../tests/test-opaque-overlay.html | 51 + .../tests/test-page-multiple-contexts.html | 19 + .../tests/test-page-pipDisabled.html | 18 + .../tests/test-page-with-iframe.html | 27 + .../tests/test-page-with-nan-video-duration.html | 14 + .../tests/test-page-with-sound.html | 20 + .../tests/test-page-with-webvtt.html | 66 ++ .../tests/test-page-without-audio.html | 18 + .../pictureinpicture/tests/test-page.html | 30 + .../tests/test-pointer-events-none.html | 21 + .../pictureinpicture/tests/test-reversed.html | 19 + .../tests/test-transparent-nested-iframes.html | 51 + .../tests/test-transparent-overlay-1.html | 46 + .../tests/test-transparent-overlay-2.html | 46 + .../pictureinpicture/tests/test-video-cropped.mp4 | Bin 0 -> 36502 bytes .../pictureinpicture/tests/test-video-long.mp4 | Bin 0 -> 344085 bytes .../tests/test-video-selection.html | 22 + .../pictureinpicture/tests/test-video-vertical.mp4 | Bin 0 -> 36502 bytes .../pictureinpicture/tests/test-video.mp4 | Bin 0 -> 242969 bytes .../pictureinpicture/tests/test-webvtt-1.vtt | 10 + .../pictureinpicture/tests/test-webvtt-2.vtt | 10 + .../pictureinpicture/tests/test-webvtt-3.vtt | 11 + .../pictureinpicture/tests/test-webvtt-4.vtt | 15 + .../pictureinpicture/tests/test-webvtt-5.vtt | 12 + 104 files changed, 11256 insertions(+) create mode 100644 toolkit/components/pictureinpicture/tests/browser.ini create mode 100644 toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_aaa_telemetry_togglePiP.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_backgroundTab.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_cannotTriggerFromContent.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_closePipPause.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_closePip_pageNavigationChanges.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_closePlayer.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_closeTab.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_close_unpip_focus.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_conflictingPips.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_contextMenu.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_controlsHover.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_cornerSnapping.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_dblclickFullscreen.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_durationChange.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_flipIconWithRTL.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_fontSize_change.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_fullscreen.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_improved_controls.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_keyboardClosePIPwithESC.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_keyboardFullScreenPIPShortcut.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_keyboardShortcut.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_keyboardShortcutClosePIP.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_keyboardShortcutWithNanDuration.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_keyboardToggle.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_mediaStreamVideos.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_mouseButtonVariation.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_multiPip.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_nimbusDisplayDuration.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_nimbusFirstTimeStyleVariant.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_nimbusMessageFirstTimePip.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_nimbusShowIconOnly.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_noPlayerControlsOnMiddleRightClick.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_noToggleOnAudio.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_occluded_window.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_playerControls.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_preserveTabPipIconOverlay.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_privateWindow.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_removeVideoElement.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_resizeVideo.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_reversePiP.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_saveLastPiPLoc.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_shortcutsAfterFocus.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_showMessage.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_smallVideoLayout.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_stripVideoStyles.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_subtitles_settings_panel.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_tabIconOverlayPiP.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_telemetry_enhancements.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_text_tracks_webvtt_1.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_text_tracks_webvtt_2.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_text_tracks_webvtt_3.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_thirdPartyIframe.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleAfterTabTearOutIn.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleButtonOnNanDuration.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleButtonOverlay.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleMode_2.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleOnInsertedVideo.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleOpaqueOverlay.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_togglePointerEventsNone.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_togglePolicies.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_togglePositionChange.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleSimple.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleTransparentOverlay-1.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggleTransparentOverlay-2.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggle_enabled.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggle_videocontrols.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_toggle_without_audio.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_touch_toggle_enablepip.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_urlbar_toggle.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_videoEmptied.js create mode 100644 toolkit/components/pictureinpicture/tests/browser_videoSelection.js create mode 100644 toolkit/components/pictureinpicture/tests/click-event-helper.js create mode 100644 toolkit/components/pictureinpicture/tests/head.js create mode 100644 toolkit/components/pictureinpicture/tests/no-audio-track.webm create mode 100644 toolkit/components/pictureinpicture/tests/short.mp4 create mode 100644 toolkit/components/pictureinpicture/tests/test-button-overlay.html create mode 100644 toolkit/components/pictureinpicture/tests/test-media-stream.html create mode 100644 toolkit/components/pictureinpicture/tests/test-opaque-overlay.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-multiple-contexts.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-pipDisabled.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-with-iframe.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-with-nan-video-duration.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-with-sound.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-with-webvtt.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page-without-audio.html create mode 100644 toolkit/components/pictureinpicture/tests/test-page.html create mode 100644 toolkit/components/pictureinpicture/tests/test-pointer-events-none.html create mode 100644 toolkit/components/pictureinpicture/tests/test-reversed.html create mode 100644 toolkit/components/pictureinpicture/tests/test-transparent-nested-iframes.html create mode 100644 toolkit/components/pictureinpicture/tests/test-transparent-overlay-1.html create mode 100644 toolkit/components/pictureinpicture/tests/test-transparent-overlay-2.html create mode 100644 toolkit/components/pictureinpicture/tests/test-video-cropped.mp4 create mode 100644 toolkit/components/pictureinpicture/tests/test-video-long.mp4 create mode 100644 toolkit/components/pictureinpicture/tests/test-video-selection.html create mode 100644 toolkit/components/pictureinpicture/tests/test-video-vertical.mp4 create mode 100644 toolkit/components/pictureinpicture/tests/test-video.mp4 create mode 100644 toolkit/components/pictureinpicture/tests/test-webvtt-1.vtt create mode 100644 toolkit/components/pictureinpicture/tests/test-webvtt-2.vtt create mode 100644 toolkit/components/pictureinpicture/tests/test-webvtt-3.vtt create mode 100644 toolkit/components/pictureinpicture/tests/test-webvtt-4.vtt create mode 100644 toolkit/components/pictureinpicture/tests/test-webvtt-5.vtt (limited to 'toolkit/components/pictureinpicture/tests') diff --git a/toolkit/components/pictureinpicture/tests/browser.ini b/toolkit/components/pictureinpicture/tests/browser.ini new file mode 100644 index 0000000000..9eccc6df9a --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser.ini @@ -0,0 +1,155 @@ +[DEFAULT] +support-files = + click-event-helper.js + head.js + short.mp4 + no-audio-track.webm + test-button-overlay.html + test-media-stream.html + test-opaque-overlay.html + test-page.html + test-page-without-audio.html + test-page-multiple-contexts.html + test-page-pipDisabled.html + test-page-with-iframe.html + test-page-with-sound.html + test-page-with-webvtt.html + test-pointer-events-none.html + test-reversed.html + test-transparent-nested-iframes.html + test-transparent-overlay-1.html + test-transparent-overlay-2.html + test-video.mp4 + test-video-cropped.mp4 + test-video-long.mp4 + test-video-selection.html + test-video-vertical.mp4 + test-webvtt-1.vtt + test-webvtt-2.vtt + test-webvtt-3.vtt + test-webvtt-4.vtt + test-webvtt-5.vtt + ../../../../dom/media/test/gizmo.mp4 + ../../../../dom/media/test/owl.mp3 + +prefs = + media.videocontrols.picture-in-picture.display-text-tracks.enabled=false + media.videocontrols.picture-in-picture.enabled=true + media.videocontrols.picture-in-picture.video-toggle.always-show=true + media.videocontrols.picture-in-picture.video-toggle.enabled=true + media.videocontrols.picture-in-picture.video-toggle.has-used=true + media.videocontrols.picture-in-picture.video-toggle.position="right" + media.videocontrols.picture-in-picture.video-toggle.testing=true + media.videocontrols.picture-in-picture.urlbar-button.enabled=true + +[browser_aaa_run_first_firstTimePiPToggleEvents.js] +[browser_aaa_telemetry_togglePiP.js] +[browser_backgroundTab.js] +[browser_cannotTriggerFromContent.js] +[browser_changePiPSrcInFullscreen.js] +[browser_closePipPause.js] +[browser_closePip_pageNavigationChanges.js] +[browser_closePlayer.js] +[browser_closeTab.js] +[browser_close_unpip_focus.js] +[browser_conflictingPips.js] +[browser_contextMenu.js] +skip-if = os == "linux" && bits == 64 && os_version == "18.04" # Bug 1569205 +[browser_controlsHover.js] +[browser_cornerSnapping.js] +run-if = os == "mac" +[browser_dblclickFullscreen.js] +[browser_durationChange.js] +[browser_flipIconWithRTL.js] +skip-if = + os == "linux" && ccov # Bug 1678091 + tsan # Bug 1678091 +[browser_fontSize_change.js] +[browser_fullscreen.js] +skip-if = (os == "mac" && debug) || os == "linux" #Bug 1566173, Bug 1664667 +[browser_improved_controls.js] +[browser_keyboardClosePIPwithESC.js] +[browser_keyboardFullScreenPIPShortcut.js] +[browser_keyboardShortcut.js] +[browser_keyboardShortcutClosePIP.js] +[browser_keyboardShortcutWithNanDuration.js] +support-files = + test-page-with-nan-video-duration.html +[browser_keyboardToggle.js] +[browser_mediaStreamVideos.js] +[browser_mouseButtonVariation.js] +skip-if = + debug + os == 'linux' && bits == 64 && !debug # Bug 1549875 +[browser_multiPip.js] +[browser_nimbusDisplayDuration.js] +[browser_nimbusFirstTimeStyleVariant.js] +[browser_nimbusMessageFirstTimePip.js] +[browser_nimbusShowIconOnly.js] +[browser_noPlayerControlsOnMiddleRightClick.js] +[browser_noToggleOnAudio.js] +[browser_occluded_window.js] +[browser_playerControls.js] +[browser_preserveTabPipIconOverlay.js] +[browser_privateWindow.js] +[browser_removeVideoElement.js] +[browser_resizeVideo.js] +skip-if = os == 'linux' # Bug 1594223 +[browser_reversePiP.js] +[browser_saveLastPiPLoc.js] +skip-if = + os == "linux" # Bug 1673465 + os == "win" && bits == 64 && debug # Bug 1683002 +[browser_shortcutsAfterFocus.js] +skip-if = os == "win" && bits == 64 && debug # Bug 1683002 +[browser_showMessage.js] +[browser_smallVideoLayout.js] +skip-if = os == "win" && bits == 64 && debug # Bug 1683002 +[browser_stripVideoStyles.js] +[browser_subtitles_settings_panel.js] +[browser_tabIconOverlayPiP.js] +[browser_telemetry_enhancements.js] +[browser_text_tracks_webvtt_1.js] +[browser_text_tracks_webvtt_2.js] +[browser_text_tracks_webvtt_3.js] +[browser_thirdPartyIframe.js] +[browser_toggleAfterTabTearOutIn.js] +skip-if = (os == 'linux' && bits == 64) || (os == 'mac' && !asan && !debug) # Bug 1605546 +[browser_toggleButtonOnNanDuration.js] +skip-if = + os == 'linux' && !debug # Bug 1700504 +support-files = + test-page-with-nan-video-duration.html +[browser_toggleButtonOverlay.js] +skip-if = true # Bug 1546455 +[browser_toggleMode_2.js] +skip-if = + os == 'linux' # Bug 1654971 + os == 'mac' # Bug 1654971 +[browser_toggleOnInsertedVideo.js] +[browser_toggleOpaqueOverlay.js] +skip-if = true # Bug 1546455 +[browser_togglePointerEventsNone.js] +skip-if = true # Bug 1664920, Bug 1628777 +[browser_togglePolicies.js] +skip-if = + os == "linux" && bits == 64 # Bug 1605565 + os == "mac" && os_version == "10.15" && debug # Bug 1605565 +[browser_togglePositionChange.js] +skip-if = + os == "linux" && bits == 64 && !debug # Bug 1738532 +[browser_toggleSimple.js] +skip-if = os == 'linux' # Bug 1546455 +[browser_toggleTransparentOverlay-1.js] +skip-if = + os == 'linux' && bits == 64 # Bug 1552288 +[browser_toggleTransparentOverlay-2.js] +skip-if = + os == 'linux' && bits == 64 && os_version == '18.04' # Bug 1546930 +[browser_toggle_enabled.js] +[browser_toggle_without_audio.js] +[browser_toggle_videocontrols.js] +[browser_touch_toggle_enablepip.js] +[browser_urlbar_toggle.js] +[browser_videoEmptied.js] +[browser_videoSelection.js] diff --git a/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js b/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js new file mode 100644 index 0000000000..f25bc602a3 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js @@ -0,0 +1,314 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { TelemetryTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryTestUtils.sys.mjs" +); + +const FIRST_TIME_PIP_TOGGLE_STYLES = { + rootID: "pictureInPictureToggle", + stages: { + hoverVideo: { + opacities: { + ".pip-wrapper": DEFAULT_TOGGLE_OPACITY, + }, + hidden: [], + }, + + hoverToggle: { + opacities: { + ".pip-wrapper": 1.0, + }, + hidden: [], + }, + }, +}; + +const FIRST_CONTEXT_MENU_EXPECTED_EVENTS = [ + [ + "pictureinpicture", + "opened_method", + "contextMenu", + null, + { firstTimeToggle: "true" }, + ], +]; + +const SECOND_CONTEXT_MENU_EXPECTED_EVENTS = [ + [ + "pictureinpicture", + "opened_method", + "contextMenu", + null, + { firstTimeToggle: "false" }, + ], +]; + +const FIRST_TOGGLE_EXPECTED_EVENTS = [ + ["pictureinpicture", "saw_toggle", "toggle", null, { firstTime: "true" }], + [ + "pictureinpicture", + "opened_method", + "toggle", + null, + { firstTimeToggle: "true" }, + ], +]; + +const SECOND_TOGGLE_EXPECTED_EVENTS = [ + ["pictureinpicture", "saw_toggle", "toggle", null, { firstTime: "false" }], + [ + "pictureinpicture", + "opened_method", + "toggle", + null, + { firstTimeToggle: "false" }, + ], +]; + +/** + * This function will open the PiP window by clicking the toggle + * and then close the PiP window + * @param browser The current browser + * @param videoID The video element id + */ +async function openAndClosePipWithToggle(browser, videoID) { + await SimpleTest.promiseFocus(browser); + await ensureVideosReady(browser); + + await prepareForToggleClick(browser, videoID); + + await clearAllContentEvents(); + + // Hover the mouse over the video to reveal the toggle, which is necessary + // if we want to click on the toggle. + await BrowserTestUtils.synthesizeMouseAtCenter( + `#${videoID}`, + { + type: "mousemove", + }, + browser + ); + await BrowserTestUtils.synthesizeMouseAtCenter( + `#${videoID}`, + { + type: "mouseover", + }, + browser + ); + + info("Waiting for toggle to become visible"); + await toggleOpacityReachesThreshold( + browser, + videoID, + "hoverVideo", + FIRST_TIME_PIP_TOGGLE_STYLES + ); + + let toggleClientRect = await getToggleClientRect(browser, videoID); + + // The toggle center, because of how it slides out, is actually outside + // of the bounds of a click event. For now, we move the mouse in by a + // hard-coded 15 pixels along the x and y axis to achieve the hover. + let toggleLeft = toggleClientRect.left + 15; + let toggleTop = toggleClientRect.top + 15; + + info("Clicking on toggle, and expecting a Picture-in-Picture window to open"); + // We need to wait for the window to have completed loading before we + // can close it as the document's type required by closeWindow may not + // be available. + let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null); + + await BrowserTestUtils.synthesizeMouseAtPoint( + toggleLeft, + toggleTop, + { + type: "mousedown", + }, + browser + ); + + await BrowserTestUtils.synthesizeMouseAtPoint( + 1, + 1, + { + type: "mouseup", + }, + browser + ); + + let win = await domWindowOpened; + ok(win, "A Picture-in-Picture window opened."); + + await SpecialPowers.spawn(browser, [videoID], async videoID => { + let video = content.document.getElementById(videoID); + await ContentTaskUtils.waitForCondition(() => { + return video.isCloningElementVisually; + }, "Video is being cloned visually."); + }); + + await BrowserTestUtils.closeWindow(win); + await assertSawMouseEvents(browser, false); + + await BrowserTestUtils.synthesizeMouseAtPoint(1, 1, {}, browser); + await assertSawMouseEvents(browser, true); +} + +/** + * This function will open the PiP window by with the context menu + * @param browser The current browser + * @param videoID The video element id + */ +async function openAndClosePipWithContextMenu(browser, videoID) { + await SimpleTest.promiseFocus(browser); + await ensureVideosReady(browser); + + let menu = document.getElementById("contentAreaContextMenu"); + let popupshown = BrowserTestUtils.waitForPopupEvent(menu, "shown"); + + await BrowserTestUtils.synthesizeMouseAtCenter( + `#${videoID}`, + { + type: "contextmenu", + }, + browser + ); + + await popupshown; + let isContextMenuOpen = menu.state === "showing" || menu.state === "open"; + ok(isContextMenuOpen, "Context menu is open"); + + let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null); + + // clear content events + await clearAllContentEvents(); + + let hidden = BrowserTestUtils.waitForPopupEvent(menu, "hidden"); + menu.activateItem(menu.querySelector("#context-video-pictureinpicture")); + await hidden; + + let win = await domWindowOpened; + ok(win, "A Picture-in-Picture window opened."); + + await SpecialPowers.spawn(browser, [videoID], async videoID => { + let video = content.document.getElementById(videoID); + await ContentTaskUtils.waitForCondition(() => { + return video.isCloningElementVisually; + }, "Video is being cloned visually."); + }); + + await BrowserTestUtils.closeWindow(win); +} + +async function clearAllContentEvents() { + // Clear everything. + await TestUtils.waitForCondition(() => { + Services.telemetry.clearEvents(); + let events = Services.telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, + true + ).content; + return !events || !events.length; + }); +} + +add_task(async function test_eventTelemetry() { + Services.telemetry.clearEvents(); + await clearAllContentEvents(); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + Services.telemetry.setEventRecordingEnabled("pictureinpicture", true); + let videoID = "no-controls"; + + const PIP_PREF = + "media.videocontrols.picture-in-picture.video-toggle.has-used"; + await SpecialPowers.pushPrefEnv({ + set: [[PIP_PREF, false]], + }); + + // open with context menu for first time + await openAndClosePipWithContextMenu(browser, videoID); + + let filter = { + category: "pictureinpicture", + method: "opened_method", + object: "contextMenu", + }; + await waitForTelemeryEvents( + filter, + FIRST_CONTEXT_MENU_EXPECTED_EVENTS.length, + "content" + ); + + TelemetryTestUtils.assertEvents( + FIRST_CONTEXT_MENU_EXPECTED_EVENTS, + filter, + { clear: true, process: "content" } + ); + + // open with toggle for first time + await SpecialPowers.pushPrefEnv({ + set: [[PIP_PREF, false]], + }); + + await openAndClosePipWithToggle(browser, videoID); + + filter = { + category: "pictureinpicture", + }; + await waitForTelemeryEvents( + filter, + FIRST_TOGGLE_EXPECTED_EVENTS.length, + "content" + ); + + TelemetryTestUtils.assertEvents(FIRST_TOGGLE_EXPECTED_EVENTS, filter, { + clear: true, + process: "content", + }); + + // open with toggle for not first time + await openAndClosePipWithToggle(browser, videoID); + + filter = { + category: "pictureinpicture", + }; + await waitForTelemeryEvents( + filter, + SECOND_TOGGLE_EXPECTED_EVENTS.length, + "content" + ); + + TelemetryTestUtils.assertEvents(SECOND_TOGGLE_EXPECTED_EVENTS, filter, { + clear: true, + process: "content", + }); + + // open with context menu for not first time + await openAndClosePipWithContextMenu(browser, videoID); + + filter = { + category: "pictureinpicture", + method: "opened_method", + object: "contextMenu", + }; + await waitForTelemeryEvents( + filter, + SECOND_CONTEXT_MENU_EXPECTED_EVENTS.length, + "content" + ); + + TelemetryTestUtils.assertEvents( + SECOND_CONTEXT_MENU_EXPECTED_EVENTS, + filter, + { true: false, process: "content" } + ); + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_aaa_telemetry_togglePiP.js b/toolkit/components/pictureinpicture/tests/browser_aaa_telemetry_togglePiP.js new file mode 100644 index 0000000000..d6a7540e15 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_aaa_telemetry_togglePiP.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function getTelemetryToggleEnabled() { + const scalarData = Services.telemetry.getSnapshotForScalars( + "main", + false + ).parent; + return scalarData["pictureinpicture.toggle_enabled"]; +} + +/** + * Tests telemetry for user toggling on or off PiP. + */ +add_task(async () => { + const TOGGLE_PIP_ENABLED_PREF = + "media.videocontrols.picture-in-picture.video-toggle.enabled"; + + await SpecialPowers.pushPrefEnv({ + set: [[TOGGLE_PIP_ENABLED_PREF, true]], + }); + + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + + let contextPiPDisable = document.getElementById( + "context_HidePictureInPictureToggle" + ); + contextPiPDisable.click(); + const enabled = Services.prefs.getBoolPref( + TOGGLE_PIP_ENABLED_PREF, + false + ); + + Assert.equal(enabled, false, "PiP is disabled."); + + await TestUtils.waitForCondition(() => { + return getTelemetryToggleEnabled() === false; + }); + + Assert.equal( + getTelemetryToggleEnabled(), + false, + "PiP is disabled according to Telemetry." + ); + + await SpecialPowers.pushPrefEnv({ + set: [[TOGGLE_PIP_ENABLED_PREF, true]], + }); + + await TestUtils.waitForCondition(() => { + return getTelemetryToggleEnabled() === true; + }); + + Assert.equal( + getTelemetryToggleEnabled(), + true, + "PiP is enabled according to Telemetry." + ); + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_backgroundTab.js b/toolkit/components/pictureinpicture/tests/browser_backgroundTab.js new file mode 100644 index 0000000000..e1f96748a5 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_backgroundTab.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +/** + * This test creates a PiP window, then switches to another tab and confirms + * that the PiP tab is still active. + */ +add_task(async () => { + let videoID = "no-controls"; + let firstTab = gBrowser.selectedTab; + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + let originatingTab = gBrowser.getTabForBrowser(browser); + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + + await BrowserTestUtils.switchTab(gBrowser, firstTab); + + let switcher = gBrowser._getSwitcher(); + + Assert.equal( + switcher.getTabState(originatingTab), + switcher.STATE_LOADED, + "The originating browser tab should be in STATE_LOADED." + ); + Assert.equal( + browser.docShellIsActive, + true, + "The docshell should be active in the originating tab" + ); + + // We need to destroy the current AsyncTabSwitcher to avoid + // tabrowser.shouldActivateDocShell going in the + // AsyncTabSwitcher.shouldActivateDocShell code path which isn't PiP aware. + switcher.destroy(); + + // Closing with window.close doesn't actually pause the video, so click + // the close button instead. + pipWin.document.getElementById("close").click(); + await BrowserTestUtils.windowClosed(pipWin); + + Assert.equal( + browser.docShellIsActive, + false, + "The docshell should be inactive in the originating tab" + ); + } + ); +}); + +/** + * This test creates a PiP window, then minimizes the browser and confirms + * that the PiP tab is still active. + */ +add_task(async () => { + let videoID = "no-controls"; + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + let originatingTab = gBrowser.getTabForBrowser(browser); + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + + let promiseSizeModeChange = BrowserTestUtils.waitForEvent( + window, + "sizemodechange" + ); + window.minimize(); + await promiseSizeModeChange; + + let switcher = gBrowser._getSwitcher(); + + Assert.equal( + switcher.getTabState(originatingTab), + switcher.STATE_LOADED, + "The originating browser tab should be in STATE_LOADED." + ); + + await BrowserTestUtils.closeWindow(pipWin); + + // Workaround bug 1782134. + window.restore(); + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_cannotTriggerFromContent.js b/toolkit/components/pictureinpicture/tests/browser_cannotTriggerFromContent.js new file mode 100644 index 0000000000..4c3d32b474 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_cannotTriggerFromContent.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the MozTogglePictureInPicture event is ignored if + * fired by unprivileged web content. + */ +add_task(async () => { + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + // For now, the easiest way to ensure that this didn't happen is to fail + // if we receive the PictureInPicture:Request message. + const MESSAGE = "PictureInPicture:Request"; + let sawMessage = false; + let listener = msg => { + sawMessage = true; + }; + browser.messageManager.addMessageListener(MESSAGE, listener); + await SpecialPowers.spawn(browser, [], async () => { + content.wrappedJSObject.fireEvents(); + }); + browser.messageManager.removeMessageListener(MESSAGE, listener); + ok(!sawMessage, "Got PictureInPicture:Request message unexpectedly."); + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js b/toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js new file mode 100644 index 0000000000..e971f17296 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js @@ -0,0 +1,511 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { sinon } = ChromeUtils.importESModule( + "resource://testing-common/Sinon.sys.mjs" +); + +const NEW_VIDEO_ASPECT_RATIO = 1.334; + +async function switchVideoSource(browser, src) { + await ContentTask.spawn(browser, { src }, async ({ src }) => { + let doc = content.document; + let video = doc.getElementById("no-controls"); + video.src = src; + }); +} + +/** + * + * @param {Object} actual The actual size and position of the window + * @param {Object} expected The expected size and position of the window + * @param {String} message A message to print before asserting the size and position + */ +function assertEvent(actual, expected, message) { + info(message); + isfuzzy( + actual.width, + expected.width, + ACCEPTABLE_DIFFERENCE, + `The actual width: ${actual.width}. The expected width: ${expected.width}` + ); + isfuzzy( + actual.height, + expected.height, + ACCEPTABLE_DIFFERENCE, + `The actual height: ${actual.height}. The expected height: ${expected.height}` + ); + isfuzzy( + actual.left, + expected.left, + ACCEPTABLE_DIFFERENCE, + `The actual left: ${actual.left}. The expected left: ${expected.left}` + ); + isfuzzy( + actual.top, + expected.top, + ACCEPTABLE_DIFFERENCE, + `The actual top: ${actual.top}. The expected top: ${expected.top}` + ); +} + +/** + * This test is our control test. This tests that when the PiP window exits + * fullscreen it will return to the size it was before being fullscreened. + */ +add_task(async function testNoSrcChangeFullscreen() { + // After opening the PiP window, it is resized to 640x360. There is a change + // the PiP window will open with that size. To prevent that we override the + // last saved position so we open at (0, 0) and 300x300. + overrideSavedPosition(0, 0, 300, 300); + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + let pipWin = await triggerPictureInPicture(browser, "no-controls"); + let controls = pipWin.document.getElementById("controls"); + const screen = pipWin.screen; + + let resizeEventArray = []; + pipWin.addEventListener("resize", event => { + let win = event.target; + let obj = { + width: win.innerWidth, + height: win.innerHeight, + left: win.screenLeft, + top: win.screenTop, + }; + resizeEventArray.push(obj); + }); + + // Move the PiP window to an unsaved location + let left = 100; + let top = 100; + pipWin.moveTo(left, top); + + await BrowserTestUtils.waitForCondition( + () => pipWin.screenLeft === 100 && pipWin.screenTop === 100, + "Waiting for PiP to move to 100, 100" + ); + + let width = 640; + let height = 360; + + let resizePromise = BrowserTestUtils.waitForEvent(pipWin, "resize"); + pipWin.resizeTo(width, height); + await resizePromise; + + Assert.equal( + resizeEventArray.length, + 1, + "resizeEventArray should have 1 event" + ); + + let actualEvent = resizeEventArray.splice(0, 1)[0]; + let expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned before fullscreen" + ); + + await promiseFullscreenEntered(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.equal( + pipWin.document.fullscreenElement, + pipWin.document.body, + "Double-click caused us to enter fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: screen.width, + height: screen.height, + left: screen.left, + top: screen.top, + }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly fullscreened before switching source" + ); + + await promiseFullscreenExited(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.ok( + !pipWin.document.fullscreenElement, + "Double-click caused us to exit fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length >= 1, + "Waiting for resizeEventArray to have 1 event, got " + + resizeEventArray.length + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + + await ensureMessageAndClosePiP(browser, "no-controls", pipWin, false); + + clearSavedPosition(); + } + ); +}); + +/** + * This function tests changing the src of a Picture-in-Picture player while + * the player is fullscreened and then ensuring the that video stays + * fullscreened after the src change and that the player will resize to the new + * video size. + */ +add_task(async function testChangingSameSizeVideoSrcFullscreen() { + // After opening the PiP window, it is resized to 640x360. There is a change + // the PiP window will open with that size. To prevent that we override the + // last saved position so we open at (0, 0) and 300x300. + overrideSavedPosition(0, 0, 300, 300); + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + let pipWin = await triggerPictureInPicture(browser, "no-controls"); + let controls = pipWin.document.getElementById("controls"); + const screen = pipWin.screen; + let sandbox = sinon.createSandbox(); + let resizeToVideoSpy = sandbox.spy(pipWin, "resizeToVideo"); + + let resizeEventArray = []; + pipWin.addEventListener("resize", event => { + let win = event.target; + let obj = { + width: win.innerWidth, + height: win.innerHeight, + left: win.screenLeft, + top: win.screenTop, + }; + resizeEventArray.push(obj); + }); + + // Move the PiP window to an unsaved location + let left = 100; + let top = 100; + pipWin.moveTo(left, top); + + await BrowserTestUtils.waitForCondition( + () => pipWin.screenLeft === 100 && pipWin.screenTop === 100, + "Waiting for PiP to move to 100, 100" + ); + + let width = 640; + let height = 360; + + let resizePromise = BrowserTestUtils.waitForEvent(pipWin, "resize"); + pipWin.resizeTo(width, height); + await resizePromise; + + Assert.equal( + resizeEventArray.length, + 1, + "resizeEventArray should have 1 event" + ); + + let actualEvent = resizeEventArray.splice(0, 1)[0]; + let expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned before fullscreen" + ); + + await promiseFullscreenEntered(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.equal( + pipWin.document.fullscreenElement, + pipWin.document.body, + "Double-click caused us to enter fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: screen.width, + height: screen.height, + left: screen.left, + top: screen.top, + }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly fullscreened before switching source" + ); + + await switchVideoSource(browser, "test-video.mp4"); + + await BrowserTestUtils.waitForCondition( + () => resizeToVideoSpy.calledOnce, + "Waiting for deferredResize to be updated" + ); + + await promiseFullscreenExited(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.ok( + !pipWin.document.fullscreenElement, + "Double-click caused us to exit fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length >= 1, + "Waiting for resizeEventArray to have 1 event, got " + + resizeEventArray.length + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + + sandbox.restore(); + await ensureMessageAndClosePiP(browser, "no-controls", pipWin, false); + + clearSavedPosition(); + } + ); +}); + +/** + * This is similar to the previous test but in this test we switch to a video + * with a different aspect ratio to confirm that the PiP window will take the + * new aspect ratio after exiting fullscreen. We also exit fullscreen with the + * escape key instead of double clicking in this test. + */ +add_task(async function testChangingDifferentSizeVideoSrcFullscreen() { + // After opening the PiP window, it is resized to 640x360. There is a change + // the PiP window will open with that size. To prevent that we override the + // last saved position so we open at (0, 0) and 300x300. + overrideSavedPosition(0, 0, 300, 300); + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + let pipWin = await triggerPictureInPicture(browser, "no-controls"); + let controls = pipWin.document.getElementById("controls"); + const screen = pipWin.screen; + let sandbox = sinon.createSandbox(); + let resizeToVideoSpy = sandbox.spy(pipWin, "resizeToVideo"); + + let resizeEventArray = []; + pipWin.addEventListener("resize", event => { + let win = event.target; + let obj = { + width: win.innerWidth, + height: win.innerHeight, + left: win.screenLeft, + top: win.screenTop, + }; + resizeEventArray.push(obj); + }); + + // Move the PiP window to an unsaved location + let left = 100; + let top = 100; + pipWin.moveTo(left, top); + + await BrowserTestUtils.waitForCondition( + () => pipWin.screenLeft === 100 && pipWin.screenTop === 100, + "Waiting for PiP to move to 100, 100" + ); + + let width = 640; + let height = 360; + + let resizePromise = BrowserTestUtils.waitForEvent(pipWin, "resize"); + pipWin.resizeTo(width, height); + await resizePromise; + + Assert.equal( + resizeEventArray.length, + 1, + "resizeEventArray should have 1 event" + ); + + let actualEvent = resizeEventArray.splice(0, 1)[0]; + let expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned before fullscreen" + ); + + await promiseFullscreenEntered(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.equal( + pipWin.document.fullscreenElement, + pipWin.document.body, + "Double-click caused us to enter fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: screen.width, + height: screen.height, + left: screen.left, + top: screen.top, + }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly fullscreened before switching source" + ); + + let previousWidth = pipWin.getDeferredResize().width; + + await switchVideoSource(browser, "test-video-long.mp4"); + + // Confirm that we are updating the `deferredResize` and not actually resizing + await BrowserTestUtils.waitForCondition( + () => resizeToVideoSpy.calledOnce, + "Waiting for deferredResize to be updated" + ); + + // Confirm that we updated the deferredResize to the new width + await BrowserTestUtils.waitForCondition( + () => previousWidth !== pipWin.getDeferredResize().width, + "Waiting for deferredResize to update" + ); + + await promiseFullscreenExited(pipWin, async () => { + EventUtils.synthesizeKey("KEY_Escape", {}, pipWin); + }); + + Assert.ok( + !pipWin.document.fullscreenElement, + "Escape key caused us to exit fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length >= 1, + "Waiting for resizeEventArray to have 1 event, got " + + resizeEventArray.length + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: height * NEW_VIDEO_ASPECT_RATIO, + height, + left, + top, + }; + + // When two resize events happen very close together we optimize by + // "coalescing" the two resizes into a single resize event. Sometimes + // the events aren't "coalesced" together (I don't know why) so I check + // if the most recent event is what we are looking for and if it is not + // then I'll wait for the resize event we are looking for. + if ( + Math.abs( + actualEvent.width - expectedEvent.width <= ACCEPTABLE_DIFFERENCE + ) + ) { + // The exit fullscreen resize events were "coalesced". + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + } else { + // For some reason the exit fullscreen resize events weren't "coalesced" + // so we have to wait for the next resize event. + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + } + + sandbox.restore(); + await ensureMessageAndClosePiP(browser, "no-controls", pipWin, false); + + clearSavedPosition(); + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_closePipPause.js b/toolkit/components/pictureinpicture/tests/browser_closePipPause.js new file mode 100644 index 0000000000..b87888e411 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_closePipPause.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This test checks that MediaStream videos are not paused when closing + * the PiP window. + */ +add_task(async function test_close_mediaStreamVideos() { + await BrowserTestUtils.withNewTab( + { + url: TEST_ROOT + "test-media-stream.html", + gBrowser, + }, + async browser => { + await SpecialPowers.spawn(browser, [], async () => { + // Construct a new video element, and capture a stream from it + // to redirect to both testing videos + let newVideo = content.document.createElement("video"); + newVideo.src = "test-video.mp4"; + newVideo.id = "media-stream-video"; + content.document.body.appendChild(newVideo); + newVideo.loop = true; + }); + await ensureVideosReady(browser); + + // Modify both the "with-controls" and "no-controls" videos so that they mirror + // the new video that we just added via MediaStream. + await SpecialPowers.spawn(browser, [], async () => { + let newVideo = content.document.getElementById("media-stream-video"); + newVideo.play(); + + for (let videoID of ["with-controls", "no-controls"]) { + let testedVideo = content.document.createElement("video"); + testedVideo.id = videoID; + testedVideo.srcObject = newVideo.mozCaptureStream().clone(); + content.document.body.prepend(testedVideo); + if ( + testedVideo.readyState < content.HTMLMediaElement.HAVE_ENOUGH_DATA + ) { + info(`Waiting for 'canplaythrough' for '${testedVideo.id}'`); + await ContentTaskUtils.waitForEvent(testedVideo, "canplaythrough"); + } + testedVideo.play(); + } + }); + + for (let videoID of ["with-controls", "no-controls"]) { + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + ok( + !(await isVideoPaused(browser, videoID)), + "The video is not paused in PiP window." + ); + + let pipClosed = BrowserTestUtils.domWindowClosed(pipWin); + let closeButton = pipWin.document.getElementById("close"); + EventUtils.synthesizeMouseAtCenter(closeButton, {}, pipWin); + await pipClosed; + ok( + !(await isVideoPaused(browser, videoID)), + "The video is not paused after closing PiP window." + ); + } + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_closePip_pageNavigationChanges.js b/toolkit/components/pictureinpicture/tests/browser_closePip_pageNavigationChanges.js new file mode 100644 index 0000000000..c64b5f2b14 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_closePip_pageNavigationChanges.js @@ -0,0 +1,113 @@ +/* Any copyright is dedicated to the Public Domain. +http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the pip window closes when the pagehide page lifecycle event + * is not detected and if a video is not loaded with a src. + */ +add_task(async function test_close_empty_pip_window() { + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + let videoID = "with-controls"; + + await ensureVideosReady(browser); + + let emptied = SpecialPowers.spawn(browser, [{ videoID }], async args => { + let video = content.document.getElementById(args.videoID); + info("Waiting for emptied event to be called"); + await ContentTaskUtils.waitForEvent(video, "emptied"); + }); + + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + + let pipClosed = BrowserTestUtils.domWindowClosed(pipWin); + await SpecialPowers.spawn(browser, [{ videoID }], async args => { + let video = content.document.getElementById(args.videoID); + video.removeAttribute("src"); + video.load(); + }); + await emptied; + await pipClosed; + } + ); +}); + +/** + * Tests that the pip window closes when navigating to another page + * via the pagehide page lifecycle event. + */ +add_task(async function test_close_pagehide() { + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + let videoID = "with-controls"; + + await ensureVideosReady(browser); + await SpecialPowers.spawn(browser, [{ videoID }], async args => { + let video = content.document.getElementById(args.videoID); + video.onemptied = () => { + // Since we handle pagehide first, handle emptied should not be invoked + ok(false, "emptied not expected to be called"); + }; + }); + + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + + let pipClosed = BrowserTestUtils.domWindowClosed(pipWin); + await SpecialPowers.spawn(browser, [{ videoID }], async args => { + content.location.href = "otherpage.html"; + }); + + await pipClosed; + } + ); +}); + +/** + * Tests that the pip window remains open if the pagehide page lifecycle + * event is not detected and if the video is still loaded with a src. + */ +add_task(async function test_open_pip_window_history_nav() { + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + let videoID = "with-controls"; + + await ensureVideosReady(browser); + + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + + await SpecialPowers.spawn(browser, [{ videoID }], async args => { + let popStatePromise = ContentTaskUtils.waitForEvent( + content, + "popstate" + ); + content.history.pushState({}, "new page", "test-page-with-sound.html"); + content.history.back(); + await popStatePromise; + }); + + ok(!pipWin.closed, "pip windows should still be open"); + + let pipClosed = BrowserTestUtils.domWindowClosed(pipWin); + let closeButton = pipWin.document.getElementById("close"); + EventUtils.synthesizeMouseAtCenter(closeButton, {}, pipWin); + await pipClosed; + } + ); +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_closePlayer.js b/toolkit/components/pictureinpicture/tests/browser_closePlayer.js new file mode 100644 index 0000000000..9b1b0a0047 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_closePlayer.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that closing with unpip leaves the video playing but the close button + * will pause the video. + */ +add_task(async () => { + for (let videoID of ["with-controls", "no-controls"]) { + info(`Testing ${videoID} case.`); + + let playVideo = () => { + return SpecialPowers.spawn(browser, [videoID], async videoID => { + return content.document.getElementById(videoID).play(); + }); + }; + + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE); + let browser = tab.linkedBrowser; + await playVideo(); + + // Try the unpip button. + let pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + ok(!(await isVideoPaused(browser, videoID)), "The video is not paused"); + + let pipClosed = BrowserTestUtils.domWindowClosed(pipWin); + let unpipButton = pipWin.document.getElementById("unpip"); + EventUtils.synthesizeMouseAtCenter(unpipButton, {}, pipWin); + await pipClosed; + ok(!(await isVideoPaused(browser, videoID)), "The video is not paused"); + + // Try the close button. + pipWin = await triggerPictureInPicture(browser, videoID); + ok(pipWin, "Got Picture-in-Picture window."); + ok(!(await isVideoPaused(browser, videoID)), "The video is not paused"); + + pipClosed = BrowserTestUtils.domWindowClosed(pipWin); + let closeButton = pipWin.document.getElementById("close"); + EventUtils.synthesizeMouseAtCenter(closeButton, {}, pipWin); + await pipClosed; + ok(await isVideoPaused(browser, videoID), "The video is paused"); + + BrowserTestUtils.removeTab(tab); + } +}); diff --git a/toolkit/components/pictureinpicture/tests/browser_closeTab.js b/toolkit/components/pictureinpicture/tests/browser_closeTab.js new file mode 100644 index 0000000000..e8c9f59d82 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_closeTab.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that if the tab that's hosting a