summaryrefslogtreecommitdiffstats
path: root/dom/media/mediacontrol/tests/browser/browser_media_control_before_media_starts.js
blob: 292c2f521f1bfbf965af5f292975e5c79d6db596 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Import this in order to use `triggerPictureInPicture()`.
Services.scriptloader.loadSubScript(
  "chrome://mochitests/content/browser/toolkit/components/pictureinpicture/tests/head.js",
  this
);

const PAGE_NON_AUTOPLAY =
  "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_non_autoplay.html";
const IFRAME_URL =
  "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_iframe_media.html";
const testVideoId = "video";

add_task(async function setupTestingPref() {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["media.mediacontrol.testingevents.enabled", true],
      ["full-screen-api.allow-trusted-requests-only", false],
    ],
  });
});

/**
 * Usually we would only start controlling media after media starts, but if
 * media has entered Picture-in-Picture mode or fullscreen, then we would allow
 * users to control them directly without prior to starting media.
 */
add_task(async function testMediaEntersPIPMode() {
  info(`open media page`);
  const tab = await createLoadedTabWrapper(PAGE_NON_AUTOPLAY);

  info(`trigger PIP mode`);
  const winPIP = await triggerPictureInPicture(tab.linkedBrowser, testVideoId);

  info(`press 'play' and wait until media starts`);
  await generateMediaControlKeyEvent("play");
  await checkOrWaitUntilMediaStartedPlaying(tab, testVideoId);

  info(`remove tab`);
  await BrowserTestUtils.closeWindow(winPIP);
  await tab.close();
});

add_task(async function testMutedMediaEntersPIPMode() {
  info(`open media page and mute video`);
  const tab = await createLoadedTabWrapper(PAGE_NON_AUTOPLAY);
  await muteMedia(tab, testVideoId);

  info(`trigger PIP mode`);
  const winPIP = await triggerPictureInPicture(tab.linkedBrowser, testVideoId);

  info(`press 'play' and wait until media starts`);
  await generateMediaControlKeyEvent("play");
  await checkOrWaitUntilMediaStartedPlaying(tab, testVideoId);

  info(`remove tab`);
  await BrowserTestUtils.closeWindow(winPIP);
  await tab.close();
});

add_task(async function testMediaEntersFullScreen() {
  info(`open media page`);
  const tab = await createLoadedTabWrapper(PAGE_NON_AUTOPLAY);

  info(`make video fullscreen`);
  await enableFullScreen(tab, testVideoId);

  info(`press 'play' and wait until media starts`);
  await generateMediaControlKeyEvent("play");
  await checkOrWaitUntilMediaStartedPlaying(tab, testVideoId);

  info(`remove tab`);
  await tab.close();
});

add_task(async function testMutedMediaEntersFullScreen() {
  info(`open media page and mute video`);
  const tab = await createLoadedTabWrapper(PAGE_NON_AUTOPLAY);
  await muteMedia(tab, testVideoId);

  info(`make video fullscreen`);
  await enableFullScreen(tab, testVideoId);

  info(`press 'play' and wait until media starts`);
  await generateMediaControlKeyEvent("play");
  await checkOrWaitUntilMediaStartedPlaying(tab, testVideoId);

  info(`remove tab`);
  await tab.close();
});

add_task(async function testNonMediaEntersFullScreen() {
  info(`open media page which won't have an activated controller`);
  // As we won't activate controller in this test case, not need to
  // check controller's status.
  const tab = await createLoadedTabWrapper(PAGE_NON_AUTOPLAY, {
    needCheck: false,
  });

  info(`make non-media element fullscreen`);
  const nonMediaElementId = "image";
  await enableFullScreen(tab, nonMediaElementId);

  info(`press 'play' which should not start media`);
  // Use `generateMediaControlKey()` directly because `play` won't affect the
  // controller's playback state (don't need to wait for the change).
  MediaControlService.generateMediaControlKey("play");
  await checkOrWaitUntilMediaStoppedPlaying(tab, testVideoId);

  info(`remove tab`);
  await tab.close();
});

add_task(async function testMediaInIframeEntersFullScreen() {
  info(`open media page`);
  const tab = await createLoadedTabWrapper(PAGE_NON_AUTOPLAY);

  info(`make video in iframe fullscreen`);
  await enableMediaFullScreenInIframe(tab, testVideoId);

  info(`press 'play' and wait until media starts`);
  await generateMediaControlKeyEvent("play");

  info(`full screen media in inframe should be started`);
  await waitUntilIframeMediaStartedPlaying(tab);

  info(`media not in fullscreen should keep paused`);
  await checkOrWaitUntilMediaStoppedPlaying(tab, testVideoId);

  info(`remove iframe that contains fullscreen video`);
  await removeIframeFromDocument(tab);

  info(`remove tab`);
  await tab.close();
});

/**
 * The following are helper functions.
 */
function muteMedia(tab, videoId) {
  return SpecialPowers.spawn(tab.linkedBrowser, [videoId], videoId => {
    content.document.getElementById(videoId).muted = true;
  });
}

function enableFullScreen(tab, elementId) {
  return SpecialPowers.spawn(tab.linkedBrowser, [elementId], elementId => {
    return new Promise(r => {
      const element = content.document.getElementById(elementId);
      element.requestFullscreen();
      element.onfullscreenchange = () => {
        element.onfullscreenchange = null;
        element.onfullscreenerror = null;
        r();
      };
      element.onfullscreenerror = () => {
        // Retry until the element successfully enters fullscreen.
        element.requestFullscreen();
      };
    });
  });
}

function enableMediaFullScreenInIframe(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [IFRAME_URL], async url => {
    info(`create iframe and wait until it finishes loading`);
    const iframe = content.document.getElementById("iframe");
    iframe.src = url;
    await new Promise(r => (iframe.onload = r));

    info(`trigger media in iframe entering into fullscreen`);
    iframe.contentWindow.postMessage("fullscreen", "*");
    info(`wait until media in frame enters fullscreen`);
    return new Promise(r => {
      content.onmessage = event => {
        is(
          event.data,
          "entered-fullscreen",
          `media in iframe entered fullscreen`
        );
        r();
      };
    });
  });
}

function waitUntilIframeMediaStartedPlaying(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [IFRAME_URL], async url => {
    info(`check if media in iframe starts playing`);
    const iframe = content.document.getElementById("iframe");
    iframe.contentWindow.postMessage("check-playing", "*");
    return new Promise(r => {
      content.onmessage = event => {
        is(event.data, "checked-playing", `media in iframe is playing`);
        r();
      };
    });
  });
}

function removeIframeFromDocument(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [], () => {
    info(`remove iframe from document`);
    content.document.getElementById("iframe").remove();
  });
}