summaryrefslogtreecommitdiffstats
path: root/docshell/test/browser/browser_bug1415918_beforeunload_options.js
blob: 4aec24cda4b04d13f10a32860ce2126fd0009b63 (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
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

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

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

SimpleTest.requestFlakyTimeout("Needs to test a timeout");

function delay(msec) {
  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
  return new Promise(resolve => setTimeout(resolve, msec));
}

function allowNextNavigation(browser) {
  return PromptTestUtils.handleNextPrompt(
    browser,
    { modalType: Services.prompt.MODAL_TYPE_CONTENT, promptType: "confirmEx" },
    { buttonNumClick: 0 }
  );
}

function cancelNextNavigation(browser) {
  return PromptTestUtils.handleNextPrompt(
    browser,
    { modalType: Services.prompt.MODAL_TYPE_CONTENT, promptType: "confirmEx" },
    { buttonNumClick: 1 }
  );
}

add_task(async function test() {
  await SpecialPowers.pushPrefEnv({
    set: [["dom.require_user_interaction_for_beforeunload", false]],
  });

  const permitUnloadTimeout = Services.prefs.getIntPref(
    "dom.beforeunload_timeout_ms"
  );

  let url = TEST_PATH + "dummy_page.html";
  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
  let browser = tab.linkedBrowser;

  await SpecialPowers.spawn(browser.browsingContext, [], () => {
    content.addEventListener("beforeunload", event => {
      event.preventDefault();
    });
  });

  /*
   * Check condition where beforeunload handlers request a prompt.
   */

  // Prompt is shown, user clicks OK.

  let promptShownPromise = allowNextNavigation(browser);
  ok(browser.permitUnload().permitUnload, "permit unload should be true");
  await promptShownPromise;

  // Prompt is shown, user clicks CANCEL.
  promptShownPromise = cancelNextNavigation(browser);
  ok(!browser.permitUnload().permitUnload, "permit unload should be false");
  await promptShownPromise;

  // Prompt is not shown, don't permit unload.
  let promptShown = false;
  let shownCallback = () => {
    promptShown = true;
  };

  browser.addEventListener("DOMWillOpenModalDialog", shownCallback);
  ok(
    !browser.permitUnload("dontUnload").permitUnload,
    "permit unload should be false"
  );
  ok(!promptShown, "prompt should not have been displayed");

  // Prompt is not shown, permit unload.
  promptShown = false;
  ok(
    browser.permitUnload("unload").permitUnload,
    "permit unload should be true"
  );
  ok(!promptShown, "prompt should not have been displayed");
  browser.removeEventListener("DOMWillOpenModalDialog", shownCallback);

  promptShownPromise = PromptTestUtils.waitForPrompt(browser, {
    modalType: Services.prompt.MODAL_TYPE_CONTENT,
    promptType: "confirmEx",
  });

  let promptDismissed = false;
  let closedCallback = () => {
    promptDismissed = true;
  };

  browser.addEventListener("DOMModalDialogClosed", closedCallback);

  let promise = browser.asyncPermitUnload();

  let promiseResolved = false;
  promise.then(() => {
    promiseResolved = true;
  });

  let dialog = await promptShownPromise;
  ok(!promiseResolved, "Should not have resolved promise yet");

  await delay(permitUnloadTimeout * 1.5);

  ok(!promptDismissed, "Should not have dismissed prompt yet");
  ok(!promiseResolved, "Should not have resolved promise yet");

  await PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 1 });

  let { permitUnload } = await promise;
  ok(promptDismissed, "Should have dismissed prompt");
  ok(!permitUnload, "Should not have permitted unload");

  browser.removeEventListener("DOMModalDialogClosed", closedCallback);

  promptShownPromise = allowNextNavigation(browser);

  /*
   * Check condition where no one requests a prompt.  In all cases,
   * permitUnload should be true, and all handlers fired.
   */
  url += "?1";
  BrowserTestUtils.loadURIString(browser, url);
  await BrowserTestUtils.browserLoaded(browser, false, url);
  await promptShownPromise;

  promptShown = false;
  browser.addEventListener("DOMWillOpenModalDialog", shownCallback);

  ok(browser.permitUnload().permitUnload, "permit unload should be true");
  ok(!promptShown, "prompt should not have been displayed");

  promptShown = false;
  ok(
    browser.permitUnload("dontUnload").permitUnload,
    "permit unload should be true"
  );
  ok(!promptShown, "prompt should not have been displayed");

  promptShown = false;
  ok(
    browser.permitUnload("unload").permitUnload,
    "permit unload should be true"
  );
  ok(!promptShown, "prompt should not have been displayed");

  browser.removeEventListener("DOMWillOpenModalDialog", shownCallback);

  await BrowserTestUtils.removeTab(tab, { skipPermitUnload: true });
});