summaryrefslogtreecommitdiffstats
path: root/dom/media/mediasession/test/browser_active_mediasession_among_tabs.js
blob: a6a1dbee688c617f1f49d341bf6e3fd4ebbade30 (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
/* eslint-disable no-undef */
"use strict";

const PAGE =
  "https://example.com/browser/dom/media/mediasession/test/file_media_session.html";

const ACTION = "previoustrack";

add_task(async function setupTestingPref() {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.media.mediasession.enabled", true],
      ["media.mediacontrol.testingevents.enabled", true],
    ],
  });
});

/**
 * When multiple tabs are all having media session, the latest created one would
 * become an active session. When the active media session is destroyed via
 * closing the tab, the previous active session would become current active
 * session again.
 */
add_task(async function testActiveSessionWhenClosingTab() {
  info(`open tab1 and load media session test page`);
  const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
  await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab1);

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab1 should become active session`);
  await checkIfActionReceived(tab1, ACTION);

  info(`open tab2 and load media session test page`);
  const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
  await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab2);

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab2 should become active session`);
  await checkIfActionReceived(tab2, ACTION);
  await checkIfActionNotReceived(tab1, ACTION);

  info(`remove tab2`);
  const controllerChanged = waitUntilMainMediaControllerChanged();
  BrowserTestUtils.removeTab(tab2);
  await controllerChanged;

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab1 should become active session again`);
  await checkIfActionReceived(tab1, ACTION);

  info(`remove tab1`);
  BrowserTestUtils.removeTab(tab1);
});

/**
 * This test is similar with `testActiveSessionWhenClosingTab`, the difference
 * is that the way we use to destroy active session is via naviagation, not
 * closing tab.
 */
add_task(async function testActiveSessionWhenNavigatingTab() {
  info(`open tab1 and load media session test page`);
  const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
  await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab1);

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab1 should become active session`);
  await checkIfActionReceived(tab1, ACTION);

  info(`open tab2 and load media session test page`);
  const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
  await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab2);

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab2 should become active session`);
  await checkIfActionReceived(tab2, ACTION);
  await checkIfActionNotReceived(tab1, ACTION);

  info(`navigate tab2 to blank page`);
  const controllerChanged = waitUntilMainMediaControllerChanged();
  BrowserTestUtils.loadURIString(tab2.linkedBrowser, "about:blank");
  await controllerChanged;

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab1 should become active session`);
  await checkIfActionReceived(tab1, ACTION);

  info(`remove tabs`);
  BrowserTestUtils.removeTab(tab1);
  BrowserTestUtils.removeTab(tab2);
});

/**
 * If we create a media session in a tab where no any playing media exists, then
 * that session would not involve in global active media session selection. The
 * current active media session would remain unchanged.
 */
add_task(async function testCreatingSessionWithoutPlayingMedia() {
  info(`open tab1 and load media session test page`);
  const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
  await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab1);

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(`session in tab1 should become active session`);
  await checkIfActionReceived(tab1, ACTION);

  info(`open tab2 and load media session test page`);
  const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);

  info(`pressing '${ACTION}' key`);
  MediaControlService.generateMediaControlKey(ACTION);

  info(
    `session in tab1 is still an active session because there is no media playing in tab2`
  );
  await checkIfActionReceived(tab1, ACTION);
  await checkIfActionNotReceived(tab2, ACTION);

  info(`remove tabs`);
  BrowserTestUtils.removeTab(tab1);
  BrowserTestUtils.removeTab(tab2);
});

/**
 * The following are helper functions
 */
async function startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab) {
  await Promise.all([
    BrowserUtils.promiseObserved("active-media-session-changed"),
    SpecialPowers.spawn(tab.linkedBrowser, [], () => {
      const video = content.document.getElementById("testVideo");
      if (!video) {
        ok(false, `can't get the media element!`);
      }
      video.play();
    }),
  ]);
}

async function checkIfActionReceived(tab, action) {
  await SpecialPowers.spawn(tab.linkedBrowser, [action], expectedAction => {
    return new Promise(resolve => {
      const result = content.document.getElementById("result");
      if (!result) {
        ok(false, `can't get the element for showing result!`);
      }

      function checkAction() {
        is(
          result.innerHTML,
          expectedAction,
          `received '${expectedAction}' correctly`
        );
        // Reset the result after finishing checking result, then we can dispatch
        // same action again without worrying about previous result.
        result.innerHTML = "";
        resolve();
      }

      if (result.innerHTML == "") {
        info(`wait until receiving action`);
        result.addEventListener("actionChanged", () => checkAction(), {
          once: true,
        });
      } else {
        checkAction();
      }
    });
  });
}

async function checkIfActionNotReceived(tab, action) {
  await SpecialPowers.spawn(tab.linkedBrowser, [action], expectedAction => {
    return new Promise(resolve => {
      const result = content.document.getElementById("result");
      if (!result) {
        ok(false, `can't get the element for showing result!`);
      }
      is(result.innerHTML, "", `should not receive any action`);
      ok(result.innerHTML != expectedAction, `not receive '${expectedAction}'`);
      resolve();
    });
  });
}

function waitUntilMainMediaControllerChanged() {
  return BrowserUtils.promiseObserved("main-media-controller-changed");
}