summaryrefslogtreecommitdiffstats
path: root/dom/tests/browser/browser_test_new_window_from_content.js
blob: e150ea3232553580aa76f1750bbe0a4d2a6db4ea (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
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/*
  We have three ways for content to open new windows:
     1) window.open (with the default features)
     2) window.open (with non-default features)
     3) target="_blank" in <a> tags

     We also have two prefs that modify our window opening behaviours:

     1) browser.link.open_newwindow

        This has a numeric value that allows us to set our window-opening behaviours from
        content in three ways:
        1) Open links that would normally open a new window in the current tab
        2) Open links that would normally open a new window in a new window
        3) Open links that would normally open a new window in a new tab (default)

     2) browser.link.open_newwindow.restriction

        This has a numeric value that allows us to fine tune the browser.link.open_newwindow
        pref so that it can discriminate between different techniques for opening windows.

        0) All things that open windows should behave according to browser.link.open_newwindow.
        1) No things that open windows should behave according to browser.link.open_newwindow
           (essentially rendering browser.link.open_newwindow inert).
        2) Most things that open windows should behave according to browser.link.open_newwindow,
           _except_ for window.open calls with the "feature" parameter. This will open in a new
           window regardless of what browser.link.open_newwindow is set at. (default)

     This file attempts to test each window opening technique against all possible settings for
     each preference.
*/

const kContentDoc =
  "https://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html";
const kNewWindowPrefKey = "browser.link.open_newwindow";
const kNewWindowRestrictionPrefKey = "browser.link.open_newwindow.restriction";
const kSameTab = "same tab";
const kNewWin = "new window";
const kNewTab = "new tab";

SpecialPowers.pushPrefEnv({
  set: [["dom.require_user_interaction_for_beforeunload", false]],
});

requestLongerTimeout(3);

// The following "matrices" represent the result of content attempting to
// open a window with window.open with the default feature set. The key of
// the kWinOpenDefault object represents the value of browser.link.open_newwindow.
// The value for each key is an array that represents the result (either opening
// the link in the same tab, a new window, or a new tab), where the index of each
// result maps to the browser.link.open_newwindow.restriction pref. I've tried
// to illustrate this more clearly in the kWinOpenDefault object.
const kWinOpenDefault = {
  //                    open_newwindow.restriction
  //                    0         1        2
  // open_newwindow
  1: [kSameTab, kNewWin, kSameTab],
  2: [kNewWin, kNewWin, kNewWin],
  3: [kNewTab, kNewWin, kNewTab],
};

const kWinOpenNonDefault = {
  1: [kSameTab, kNewWin, kNewWin],
  2: [kNewWin, kNewWin, kNewWin],
  3: [kNewTab, kNewWin, kNewWin],
};

const kTargetBlank = {
  1: [kSameTab, kSameTab, kSameTab],
  2: [kNewWin, kNewWin, kNewWin],
  3: [kNewTab, kNewTab, kNewTab],
};

// We'll be changing these preferences a lot, so we'll stash their original
// values and make sure we restore them at the end of the test.
var originalNewWindowPref = Services.prefs.getIntPref(kNewWindowPrefKey);
var originalNewWindowRestrictionPref = Services.prefs.getIntPref(
  kNewWindowRestrictionPrefKey
);

registerCleanupFunction(function () {
  Services.prefs.setIntPref(kNewWindowPrefKey, originalNewWindowPref);
  Services.prefs.setIntPref(
    kNewWindowRestrictionPrefKey,
    originalNewWindowRestrictionPref
  );
});

/**
 * For some expectation when a link is clicked, creates and
 * returns a Promise that resolves when that expectation is
 * fulfilled. For example, aExpectation might be kSameTab, which
 * will cause this function to return a Promise that resolves when
 * the current tab attempts to browse to about:blank.
 *
 * This function also takes care of cleaning up once the result has
 * occurred - for example, if a new window was opened, this function
 * closes it before resolving.
 *
 * @param aBrowser the <xul:browser> with the test document
 * @param aExpectation one of kSameTab, kNewWin, or kNewTab.
 * @return a Promise that resolves when the expectation is fulfilled,
 *         and cleaned up after.
 */
function prepareForResult(aBrowser, aExpectation) {
  let expectedSpec = kContentDoc.replace(/[^\/]*$/, "dummy.html");
  switch (aExpectation) {
    case kSameTab:
      return (async function () {
        await BrowserTestUtils.browserLoaded(aBrowser);
        is(aBrowser.currentURI.spec, expectedSpec, "Should be at dummy.html");
        // Now put the browser back where it came from
        BrowserTestUtils.loadURIString(aBrowser, kContentDoc);
        await BrowserTestUtils.browserLoaded(aBrowser);
      })();
    case kNewWin:
      return (async function () {
        let newWin = await BrowserTestUtils.waitForNewWindow({
          url: expectedSpec,
        });
        let newBrowser = newWin.gBrowser.selectedBrowser;
        is(newBrowser.currentURI.spec, expectedSpec, "Should be at dummy.html");
        await BrowserTestUtils.closeWindow(newWin);
      })();
    case kNewTab:
      return (async function () {
        let newTab = await BrowserTestUtils.waitForNewTab(gBrowser);
        is(
          newTab.linkedBrowser.currentURI.spec,
          expectedSpec,
          "Should be at dummy.html"
        );
        BrowserTestUtils.removeTab(newTab);
      })();
    default:
      ok(
        false,
        "prepareForResult can't handle an expectation of " + aExpectation
      );
      return Promise.resolve();
  }
}

/**
 * Ensure that clicks on a link with ID aLinkID cause us to
 * perform as specified in the supplied aMatrix (kWinOpenDefault,
 * for example).
 *
 * @param aLinkSelector a selector for the link within the testing page to click.
 * @param aMatrix a testing matrix for the
 *        browser.link.open_newwindow and browser.link.open_newwindow.restriction
 *        prefs to test against. See kWinOpenDefault for an example.
 */
function testLinkWithMatrix(aLinkSelector, aMatrix) {
  return BrowserTestUtils.withNewTab(
    {
      gBrowser,
      url: kContentDoc,
    },
    async function (browser) {
      // This nested for-loop is unravelling the matrix const
      // we set up, and gives us three things through each tick
      // of the inner loop:
      // 1) newWindowPref: a browser.link.open_newwindow pref to try
      // 2) newWindowRestPref: a browser.link.open_newwindow.restriction pref to try
      // 3) expectation: what we expect the click outcome on this link to be,
      //                 which will either be kSameTab, kNewWin or kNewTab.
      for (let newWindowPref in aMatrix) {
        let expectations = aMatrix[newWindowPref];
        for (let i = 0; i < expectations.length; ++i) {
          let newWindowRestPref = i;
          let expectation = expectations[i];

          Services.prefs.setIntPref(
            "browser.link.open_newwindow",
            newWindowPref
          );
          Services.prefs.setIntPref(
            "browser.link.open_newwindow.restriction",
            newWindowRestPref
          );
          info("Clicking on " + aLinkSelector);
          info(
            "Testing with browser.link.open_newwindow = " +
              newWindowPref +
              " and " +
              "browser.link.open_newwindow.restriction = " +
              newWindowRestPref
          );
          info("Expecting: " + expectation);
          let resultPromise = prepareForResult(browser, expectation);
          BrowserTestUtils.synthesizeMouseAtCenter(aLinkSelector, {}, browser);
          await resultPromise;
          info("Got expectation: " + expectation);
        }
      }
    }
  );
}

add_task(async function test_window_open_with_defaults() {
  await testLinkWithMatrix("#winOpenDefault", kWinOpenDefault);
});

add_task(async function test_window_open_with_non_defaults() {
  await testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault);
});

add_task(async function test_window_open_dialog() {
  await testLinkWithMatrix("#winOpenDialog", kWinOpenNonDefault);
});

add_task(async function test_target__blank() {
  await testLinkWithMatrix("#targetBlank", kTargetBlank);
});