summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
blob: d95faa9665fd3b972a5d6981dea8dadbb585a347 (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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
"use strict";

const { PermissionTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/PermissionTestUtils.sys.mjs"
);

const ROOT = getRootDirectory(gTestPath).replace(
  "chrome://mochitests/content/",
  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
  "http://example.com/"
);
let pageWithAlert = ROOT + "openPromptOffTimeout.html";

registerCleanupFunction(function () {
  Services.perms.removeAll();
});

/*
 * This test opens a tab that alerts when it is hidden. We then switch away
 * from the tab, and check that by default the tab is not automatically
 * re-selected. We also check that a checkbox appears in the alert that allows
 * the user to enable this automatically re-selecting. We then check that
 * checking the checkbox does actually enable that behaviour.
 */
add_task(async function test_old_modal_ui() {
  // We're intentionally testing the old modal mechanism, so disable the new one.
  await SpecialPowers.pushPrefEnv({
    set: [["prompts.contentPromptSubDialog", false]],
  });

  let firstTab = gBrowser.selectedTab;
  // load page that opens prompt when page is hidden
  let openedTab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    pageWithAlert,
    true
  );
  let openedTabGotAttentionPromise = BrowserTestUtils.waitForAttribute(
    "attention",
    openedTab
  );
  // switch away from that tab again - this triggers the alert.
  await BrowserTestUtils.switchTab(gBrowser, firstTab);
  // ... but that's async on e10s...
  await openedTabGotAttentionPromise;
  // check for attention attribute
  is(
    openedTab.hasAttribute("attention"),
    true,
    "Tab with alert should have 'attention' attribute."
  );
  ok(!openedTab.selected, "Tab with alert should not be selected");

  // switch tab back, and check the checkbox is displayed:
  await BrowserTestUtils.switchTab(gBrowser, openedTab);
  // check the prompt is there, and the extra row is present
  let promptElements =
    openedTab.linkedBrowser.parentNode.querySelectorAll("tabmodalprompt");
  is(promptElements.length, 1, "There should be 1 prompt");
  let ourPromptElement = promptElements[0];
  let checkbox = ourPromptElement.querySelector(
    "checkbox[label*='example.com']"
  );
  ok(checkbox, "The checkbox should be there");
  ok(!checkbox.checked, "Checkbox shouldn't be checked");
  // tick box and accept dialog
  checkbox.checked = true;
  let ourPrompt =
    openedTab.linkedBrowser.tabModalPromptBox.getPrompt(ourPromptElement);
  ourPrompt.onButtonClick(0);
  // Wait for that click to actually be handled completely.
  await new Promise(function (resolve) {
    Services.tm.dispatchToMainThread(resolve);
  });
  // check permission is set
  is(
    Services.perms.ALLOW_ACTION,
    PermissionTestUtils.testPermission(pageWithAlert, "focus-tab-by-prompt"),
    "Tab switching should now be allowed"
  );

  // Check if the control center shows the correct permission.
  let shown = BrowserTestUtils.waitForEvent(
    window,
    "popupshown",
    true,
    event => event.target == gPermissionPanel._permissionPopup
  );
  gPermissionPanel._identityPermissionBox.click();
  await shown;
  let labelText = SitePermissions.getPermissionLabel("focus-tab-by-prompt");
  let permissionsList = document.getElementById(
    "permission-popup-permission-list"
  );
  let label = permissionsList.querySelector(
    ".permission-popup-permission-label"
  );
  is(label.textContent, labelText);
  gPermissionPanel._permissionPopup.hidePopup();

  // Check if the identity icon signals granted permission.
  ok(
    gPermissionPanel._identityPermissionBox.hasAttribute("hasPermissions"),
    "identity-box signals granted permissions"
  );

  let openedTabSelectedPromise = BrowserTestUtils.waitForAttribute(
    "selected",
    openedTab,
    "true"
  );
  // switch to other tab again
  await BrowserTestUtils.switchTab(gBrowser, firstTab);

  // This is sync in non-e10s, but in e10s we need to wait for this, so yield anyway.
  // Note that the switchTab promise doesn't actually guarantee anything about *which*
  // tab ends up as selected when its event fires, so using that here wouldn't work.
  await openedTabSelectedPromise;
  // should be switched back
  ok(openedTab.selected, "Ta-dah, the other tab should now be selected again!");

  // In e10s, with the conformant promise scheduling, we have to wait for next tick
  // to ensure that the prompt is open before removing the opened tab, because the
  // promise callback of 'openedTabSelectedPromise' could be done at the middle of
  // RemotePrompt.openTabPrompt() while 'DOMModalDialogClosed' event is fired.
  await TestUtils.waitForTick();

  BrowserTestUtils.removeTab(openedTab);
});

add_task(async function test_new_modal_ui() {
  // We're intentionally testing the new modal mechanism, so make sure it's enabled.
  await SpecialPowers.pushPrefEnv({
    set: [["prompts.contentPromptSubDialog", true]],
  });

  // Make sure we clear the focus tab permission set in the previous test
  PermissionTestUtils.remove(pageWithAlert, "focus-tab-by-prompt");

  let firstTab = gBrowser.selectedTab;
  // load page that opens prompt when page is hidden
  let openedTab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    pageWithAlert,
    true
  );
  let openedTabGotAttentionPromise = BrowserTestUtils.waitForAttribute(
    "attention",
    openedTab
  );
  // switch away from that tab again - this triggers the alert.
  await BrowserTestUtils.switchTab(gBrowser, firstTab);
  // ... but that's async on e10s...
  await openedTabGotAttentionPromise;
  // check for attention attribute
  is(
    openedTab.hasAttribute("attention"),
    true,
    "Tab with alert should have 'attention' attribute."
  );
  ok(!openedTab.selected, "Tab with alert should not be selected");

  // switch tab back, and check the checkbox is displayed:
  await BrowserTestUtils.switchTab(gBrowser, openedTab);
  // check the prompt is there
  let promptElements = openedTab.linkedBrowser.parentNode.querySelectorAll(
    ".content-prompt-dialog"
  );

  let dialogBox = gBrowser.getTabDialogBox(openedTab.linkedBrowser);
  let contentPromptManager = dialogBox.getContentDialogManager();
  is(promptElements.length, 1, "There should be 1 prompt");
  is(
    contentPromptManager._dialogs.length,
    1,
    "Content prompt manager should have 1 dialog box."
  );

  // make sure the checkbox appears and that the permission for allowing tab switching
  // is set when the checkbox is tickted and the dialog is accepted
  let dialog = contentPromptManager._dialogs[0];

  await dialog._dialogReady;

  let dialogDoc = dialog._frame.contentWindow.document;
  let checkbox = dialogDoc.querySelector("checkbox[label*='example.com']");
  let button = dialogDoc.querySelector("#commonDialog").getButton("accept");

  ok(checkbox, "The checkbox should be there");
  ok(!checkbox.checked, "Checkbox shouldn't be checked");

  // tick box and accept dialog
  checkbox.checked = true;
  button.click();
  // Wait for that click to actually be handled completely.
  await new Promise(function (resolve) {
    Services.tm.dispatchToMainThread(resolve);
  });

  ok(!contentPromptManager._dialogs.length, "Dialog should be closed");

  // check permission is set
  is(
    Services.perms.ALLOW_ACTION,
    PermissionTestUtils.testPermission(pageWithAlert, "focus-tab-by-prompt"),
    "Tab switching should now be allowed"
  );

  // Check if the control center shows the correct permission.
  let shown = BrowserTestUtils.waitForEvent(
    window,
    "popupshown",
    true,
    event => event.target == gPermissionPanel._permissionPopup
  );
  gPermissionPanel._identityPermissionBox.click();
  await shown;
  let labelText = SitePermissions.getPermissionLabel("focus-tab-by-prompt");
  let permissionsList = document.getElementById(
    "permission-popup-permission-list"
  );
  let label = permissionsList.querySelector(
    ".permission-popup-permission-label"
  );
  is(label.textContent, labelText);
  gPermissionPanel.hidePopup();

  // Check if the identity icon signals granted permission.
  ok(
    gPermissionPanel._identityPermissionBox.hasAttribute("hasPermissions"),
    "identity-permission-box signals granted permissions"
  );

  let openedTabSelectedPromise = BrowserTestUtils.waitForAttribute(
    "selected",
    openedTab,
    "true"
  );

  // switch to other tab again
  await BrowserTestUtils.switchTab(gBrowser, firstTab);

  // This is sync in non-e10s, but in e10s we need to wait for this, so yield anyway.
  // Note that the switchTab promise doesn't actually guarantee anything about *which*
  // tab ends up as selected when its event fires, so using that here wouldn't work.
  await openedTabSelectedPromise;

  ok(contentPromptManager._dialogs.length === 1, "Dialog opened.");
  dialog = contentPromptManager._dialogs[0];
  await dialog._dialogReady;

  // should be switched back
  ok(openedTab.selected, "Ta-dah, the other tab should now be selected again!");

  // In e10s, with the conformant promise scheduling, we have to wait for next tick
  // to ensure that the prompt is open before removing the opened tab, because the
  // promise callback of 'openedTabSelectedPromise' could be done at the middle of
  // RemotePrompt.openTabPrompt() while 'DOMModalDialogClosed' event is fired.
  // await TestUtils.waitForTick();

  await BrowserTestUtils.removeTab(openedTab);
});