summaryrefslogtreecommitdiffstats
path: root/browser/components/sessionstore/test/browser_restore_container_tabs_oa.js
blob: c80a2d710b8b43ae41041e7c27a5f96391cf6aa5 (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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const PATH = "browser/browser/components/sessionstore/test/empty.html";

/* import-globals-from ../../../base/content/test/tabs/helper_origin_attrs_testing.js */
loadTestSubscript(
  "../../../base/content/test/tabs/helper_origin_attrs_testing.js"
);

var TEST_CASES = [
  "https://example.com/" + PATH,
  "https://example.org/" + PATH,
  "about:preferences",
  "about:config",
];

var remoteTypes;

var xulFrameLoaderCreatedCounter = {};

function handleEventLocal(aEvent) {
  if (aEvent.type != "XULFrameLoaderCreated") {
    return;
  }
  // Ignore <browser> element in about:preferences and any other special pages
  if ("gBrowser" in aEvent.target.ownerGlobal) {
    xulFrameLoaderCreatedCounter.numCalledSoFar++;
  }
}

var NUM_DIFF_TAB_MODES = NUM_USER_CONTEXTS + 1; /** regular tab */

add_setup(async function () {
  await SpecialPowers.pushPrefEnv({
    set: [
      // Set the pref to true so we know exactly how many tabs should be restoring at
      // any given time. This guarantees that a finishing load won't start another.
      ["browser.sessionstore.restore_on_demand", true],
      // Don't restore tabs lazily.
      ["browser.sessionstore.restore_tabs_lazily", true],
      // don't preload tabs so we don't have extra XULFrameLoaderCreated events
      // firing
      ["browser.newtab.preload", false],
    ],
  });

  requestLongerTimeout(7);
});

function setupRemoteTypes() {
  if (gFissionBrowser) {
    remoteTypes = [
      "webIsolated=https://example.com",
      "webIsolated=https://example.com^userContextId=1",
      "webIsolated=https://example.com^userContextId=2",
      "webIsolated=https://example.com^userContextId=3",
      "webIsolated=https://example.org",
      "webIsolated=https://example.org^userContextId=1",
      "webIsolated=https://example.org^userContextId=2",
      "webIsolated=https://example.org^userContextId=3",
    ];
  } else {
    remoteTypes = Array(
      NUM_DIFF_TAB_MODES * 2 /** 2 is the number of non parent uris */
    ).fill("web");
  }
  remoteTypes.push(...Array(NUM_DIFF_TAB_MODES * 2).fill(null)); // remote types for about: pages

  forgetClosedWindows();
  is(SessionStore.getClosedWindowCount(), 0, "starting with no closed windows");
}
/*
 * 1. Open several tabs in different containers and in regular tabs
 [page1, page2, page3] [ [(page1 - work) (page1 - home)] [(page2 - work) (page2 - home)] ]
 * 2. Close the window
 * 3. Restore session, window will have the following tabs
 * [initial blank page, page1, page1-work, page1-home, page2, page2-work, page2-home] 
 * 4. Verify correct remote types and that XULFrameLoaderCreated gets fired correct number of times
 */
add_task(async function testRestore() {
  setupRemoteTypes();
  let newWin = await promiseNewWindowLoaded();
  var regularPages = [];
  var containerPages = {};
  // Go through all the test cases and open same set of urls in regular tabs and in container tabs
  for (const uri of TEST_CASES) {
    // Open a url in a regular tab
    let regularPage = await openURIInRegularTab(uri, newWin);
    regularPages.push(regularPage);

    // Open the same url in different user contexts
    for (
      var user_context_id = 1;
      user_context_id <= NUM_USER_CONTEXTS;
      user_context_id++
    ) {
      let containerPage = await openURIInContainer(
        uri,
        newWin,
        user_context_id
      );
      containerPages[uri] = containerPage;
    }
  }
  await TabStateFlusher.flushWindow(newWin);

  // Close the window
  await BrowserTestUtils.closeWindow(newWin);
  await forceSaveState();

  is(
    SessionStore.getClosedWindowCount(),
    1,
    "Should have restore data for the closed window"
  );

  // Now restore the window
  newWin = SessionStore.undoCloseWindow(0);

  // Make sure to wait for the window to be restored.
  await Promise.all([
    BrowserTestUtils.waitForEvent(newWin, "SSWindowStateReady"),
  ]);
  await BrowserTestUtils.waitForEvent(
    newWin.gBrowser.tabContainer,
    "SSTabRestored"
  );

  var nonblank_pages_len =
    TEST_CASES.length + NUM_USER_CONTEXTS * TEST_CASES.length;
  is(
    newWin.gBrowser.tabs.length,
    nonblank_pages_len + 1 /* initial page */,
    "Correct number of tabs restored"
  );

  // Now we have pages opened in the following manner
  // [blank page, page1, page1-work, page1-home, page2, page2-work, page2-home]

  info(`Number of tabs restored: ${newWin.gBrowser.tabs.length}`);
  var currRemoteType, expectedRemoteType;
  let loaded;
  for (var tab_idx = 1; tab_idx < nonblank_pages_len; ) {
    info(`Accessing regular tab at index ${tab_idx}`);
    var test_page_data = regularPages.shift();
    let regular_tab = newWin.gBrowser.tabs[tab_idx];
    let regular_browser = regular_tab.linkedBrowser;

    // I would have used browserLoaded but for about:config it doesn't work
    let ready = BrowserTestUtils.waitForCondition(async () => {
      // Catch an error because the browser might change remoteness in between
      // calls, so we will just wait for the document to finish loadig.
      return SpecialPowers.spawn(regular_browser, [], () => {
        return content.document.readyState == "complete";
      }).catch(console.error);
    });
    newWin.gBrowser.selectedTab = regular_tab;
    await TabStateFlusher.flush(regular_browser);
    await ready;

    currRemoteType = regular_browser.remoteType;
    expectedRemoteType = remoteTypes.shift();
    is(
      currRemoteType,
      expectedRemoteType,
      `correct remote type for regular tab with uri ${test_page_data.uri}`
    );

    let page_uri = regular_browser.currentURI.spec;
    info(`Current uri = ${page_uri}`);

    // Iterate over container pages, starting after the regular page and ending before the next regular page
    var userContextId = 1;
    for (
      var container_tab_idx = tab_idx + 1;
      container_tab_idx < tab_idx + 1 + NUM_USER_CONTEXTS;
      container_tab_idx++, userContextId++
    ) {
      info(`Accessing container tab at index ${container_tab_idx}`);
      let container_tab = newWin.gBrowser.tabs[container_tab_idx];

      initXulFrameLoaderCreatedCounter(xulFrameLoaderCreatedCounter);
      container_tab.ownerGlobal.gBrowser.addEventListener(
        "XULFrameLoaderCreated",
        handleEventLocal
      );

      loaded = BrowserTestUtils.browserLoaded(
        container_tab.linkedBrowser,
        false,
        test_page_data.uri
      );

      newWin.gBrowser.selectedTab = container_tab;
      await TabStateFlusher.flush(container_tab.linkedBrowser);
      await loaded;
      let uri = container_tab.linkedBrowser.currentURI.spec;

      // Verify XULFrameLoaderCreated was fired once
      is(
        xulFrameLoaderCreatedCounter.numCalledSoFar,
        1,
        `XULFrameLoaderCreated was fired once, when restoring ${uri} in container ${userContextId} `
      );
      container_tab.ownerGlobal.gBrowser.removeEventListener(
        "XULFrameLoaderCreated",
        handleEventLocal
      );

      // Verify correct remote type for container tab
      currRemoteType = container_tab.linkedBrowser.remoteType;
      expectedRemoteType = remoteTypes.shift();
      info(
        `Remote type for container tab ${userContextId} is ${currRemoteType}`
      );
      is(
        currRemoteType,
        expectedRemoteType,
        "correct remote type for container tab"
      );
    }
    // Advance to the next regular page in our tabs list
    tab_idx = container_tab_idx;
  }

  await BrowserTestUtils.closeWindow(newWin);
});